From 827b43b3ca17b5a8de2fdac367ec9140385f7b31 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Wed, 13 May 2020 13:48:12 -0700 Subject: [PATCH] RADIUS client: Support SO_BINDTODEVICE Allow the RADIUS client socket to be bound to a specific netdev. This helps hostapd work better in VRF and other fancy network environments. Signed-off-by: Ben Greear Signed-off-by: Andreas Tobler --- hostapd/config_file.c | 3 +++ hostapd/hostapd.conf | 6 ++++++ src/ap/ap_config.c | 1 + src/radius/radius_client.c | 29 ++++++++++++++++++++++++----- src/radius/radius_client.h | 5 +++++ 5 files changed, 39 insertions(+), 5 deletions(-) diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 64704fb3d..80842b8f4 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -2711,6 +2711,9 @@ static int hostapd_config_fill(struct hostapd_config *conf, return 1; } bss->radius->force_client_addr = 1; + } else if (os_strcmp(buf, "radius_client_dev") == 0) { + os_free(bss->radius->force_client_dev); + bss->radius->force_client_dev = os_strdup(pos); } else if (os_strcmp(buf, "auth_server_addr") == 0) { if (hostapd_config_read_radius_addr( &bss->radius->auth_servers, diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index a3d28efed..8958abd16 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -1381,6 +1381,12 @@ own_ip_addr=127.0.0.1 # used, e.g., when the device has multiple IP addresses. #radius_client_addr=127.0.0.1 +# RADIUS client forced local interface. Helps run properly with VRF +# Default is none set which allows the network stack to pick the appropriate +# interface automatically. +# Example below binds to eth0 +#radius_client_dev=eth0 + # RADIUS authentication server #auth_server_addr=127.0.0.1 #auth_server_port=1812 diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index 419bf7cad..611fa2e2c 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -779,6 +779,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf) conf->radius->num_auth_servers); hostapd_config_free_radius(conf->radius->acct_servers, conf->radius->num_acct_servers); + os_free(conf->radius->force_client_dev); } hostapd_config_free_radius_attr(conf->radius_auth_req_attr); hostapd_config_free_radius_attr(conf->radius_acct_req_attr); diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c index bfcb9442b..4f0ff0754 100644 --- a/src/radius/radius_client.c +++ b/src/radius/radius_client.c @@ -7,6 +7,7 @@ */ #include "includes.h" +#include #include "common.h" #include "radius.h" @@ -1168,6 +1169,29 @@ radius_change_server(struct radius_client_data *radius, return -1; } + /* Force a reconnect by disconnecting the socket first */ + if (connect(sel_sock, (struct sockaddr *) &disconnect_addr, + sizeof(disconnect_addr)) < 0) + wpa_printf(MSG_INFO, "disconnect[radius]: %s", strerror(errno)); + +#ifdef __linux__ + if (conf->force_client_dev && conf->force_client_dev[0]) { + if (setsockopt(sel_sock, SOL_SOCKET, SO_BINDTODEVICE, + conf->force_client_dev, + os_strlen(conf->force_client_dev)) < 0) { + wpa_printf(MSG_ERROR, + "RADIUS: setsockopt[SO_BINDTODEVICE]: %s", + strerror(errno)); + /* Probably not a critical error; continue on and hope + * for the best. */ + } else { + wpa_printf(MSG_DEBUG, + "RADIUS: Bound client socket to device: %s", + conf->force_client_dev); + } + } +#endif /* __linux__ */ + if (conf->force_client_addr) { switch (conf->client_addr.af) { case AF_INET: @@ -1200,11 +1224,6 @@ radius_change_server(struct radius_client_data *radius, } } - /* Force a reconnect by disconnecting the socket first */ - if (connect(sel_sock, (struct sockaddr *) &disconnect_addr, - sizeof(disconnect_addr)) < 0) - wpa_printf(MSG_INFO, "disconnect[radius]: %s", strerror(errno)); - if (connect(sel_sock, addr, addrlen) < 0) { wpa_printf(MSG_INFO, "connect[radius]: %s", strerror(errno)); return -1; diff --git a/src/radius/radius_client.h b/src/radius/radius_client.h index 8ca0874db..687cd81ae 100644 --- a/src/radius/radius_client.h +++ b/src/radius/radius_client.h @@ -174,6 +174,11 @@ struct hostapd_radius_servers { * force_client_addr - Whether to force client (local) address */ int force_client_addr; + + /** + * force_client_dev - Bind the socket to a specified interface, if set + */ + char *force_client_dev; };