[PATCH 1/1] Add FQDN support for auth and acct server addresses
Magnus Malm
magnusmalm at gmail.com
Fri Dec 3 03:18:41 PST 2021
This patch adds support to configure Fully Qualified Domain Names (FQDN)
for authentication and accounting server addresses.
Signed-off-by: Magnus Malm <magnusmalm at gmail.com>
---
hostapd/config_file.c | 31 ++++++++++++++-
src/radius/radius_client.c | 13 ++++++-
src/radius/radius_client.h | 3 ++
src/utils/ip_addr.c | 77 ++++++++++++++++++++++++++++++++++++++
src/utils/ip_addr.h | 1 +
5 files changed, 123 insertions(+), 2 deletions(-)
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index daf3f37ad..2e4aef0b5 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -24,6 +24,7 @@
#include "ap/wpa_auth.h"
#include "ap/ap_config.h"
#include "config_file.h"
+#include "ip_addr.h"
#ifndef CONFIG_NO_VLAN
@@ -627,6 +628,21 @@ static int hostapd_config_read_eap_user(const char *fname,
#ifndef CONFIG_NO_RADIUS
+
+static int radius_parse_fqdn(const char *fqdn,
+ struct hostapd_radius_server *nserv)
+{
+ size_t len = strnlen(fqdn, NI_MAXHOST);
+
+ if (len < 1)
+ return -1;
+
+ strncpy(nserv->fqdn_addr, fqdn, len);
+ nserv->fqdn_addr[len + 1] = '\0';
+
+ return 1;
+}
+
static int
hostapd_config_read_radius_addr(struct hostapd_radius_server **server,
int *num_server, const char *val, int def_port,
@@ -648,7 +664,20 @@ hostapd_config_read_radius_addr(struct hostapd_radius_server **server,
os_memset(nserv, 0, sizeof(*nserv));
nserv->port = def_port;
ret = hostapd_parse_ip_addr(val, &nserv->addr);
- nserv->index = server_index++;
+
+ /* RADIUS address is not a valid IP address, see if it's a FQDN */
+ if (ret) {
+ if ((radius_parse_fqdn(val, nserv) < 0)) {
+ wpa_printf(MSG_ERROR, "FQDN %s parse failed", val);
+ return -1;
+ } else {
+ nserv->resolved = resolve_fqdn(nserv->fqdn_addr, &nserv->addr);
+ if (!nserv->resolved)
+ wpa_printf(MSG_INFO, "FQDN %s resolve failed", nserv->fqdn_addr);
+ }
+ ret = 0;
+ }
+ nserv->index = server_index++;
return ret;
}
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index ee9e46d2a..47f2aa96a 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -1136,7 +1136,18 @@ radius_change_server(struct radius_client_data *radius,
radius_client_timer, radius, NULL);
}
- switch (nserv->addr.af) {
+ /* If FQDN is confiured but it was not resolved when the config file was
+ * read at startup, try again. */
+ if ((os_strncmp("", nserv->fqdn_addr, sizeof(nserv->fqdn_addr)) != 0) &&
+ !nserv->resolved) {
+ nserv->resolved = resolve_fqdn(nserv->fqdn_addr, &nserv->addr);
+ if (!nserv->resolved) {
+ wpa_printf(MSG_ERROR, "FQDN %s failed to be resolved", nserv->fqdn_addr);
+ return -1;
+ }
+ }
+
+ switch (nserv->addr.af) {
case AF_INET:
os_memset(&serv, 0, sizeof(serv));
serv.sin_family = AF_INET;
diff --git a/src/radius/radius_client.h b/src/radius/radius_client.h
index 687cd81ae..989209ef3 100644
--- a/src/radius/radius_client.h
+++ b/src/radius/radius_client.h
@@ -9,6 +9,7 @@
#ifndef RADIUS_CLIENT_H
#define RADIUS_CLIENT_H
+#include <netdb.h>
#include "ip_addr.h"
struct radius_msg;
@@ -29,6 +30,8 @@ struct hostapd_radius_server {
* addr - radiusAuthServerAddress or radiusAccServerAddress
*/
struct hostapd_ip_addr addr;
+ char fqdn_addr[NI_MAXHOST];
+ int resolved;
/**
* port - radiusAuthClientServerPortNumber or radiusAccClientServerPortNumber
diff --git a/src/utils/ip_addr.c b/src/utils/ip_addr.c
index 92a359039..96a7b3b29 100644
--- a/src/utils/ip_addr.c
+++ b/src/utils/ip_addr.c
@@ -6,11 +6,88 @@
* See README for more details.
*/
+#include <netdb.h>
+#include <resolv.h>
+
#include "includes.h"
#include "common.h"
#include "ip_addr.h"
+/**
+ * Do a DNS lookup on fqdn_addr and, if successful, set addr accordingly. If
+ * resolve fails, return 0, otherwise 1.
+ */
+int resolve_fqdn(const char *fqdn_addr, struct hostapd_ip_addr *addr)
+{
+ struct addrinfo *servinfo = NULL;
+ struct addrinfo hints;
+ struct addrinfo *next = NULL;
+ int sfd = 0;
+ int rc = 0;
+
+ /* Ensure we do not get old DNS entries from getaddrinfo() */
+ res_init();
+
+ os_memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC; /* IPv4 or IPv6*/
+ hints.ai_socktype = SOCK_DGRAM; /* DGRAM sockets only */
+ hints.ai_protocol = IPPROTO_UDP; /* UDP only */
+ hints.ai_flags = AI_NUMERICSERV; /* No service name lookup */
+
+ rc = getaddrinfo(fqdn_addr, NULL, &hints, &servinfo);
+ if (rc != 0 || !servinfo) {
+ freeaddrinfo(servinfo);
+ return 0;
+ }
+
+ /* For each addrinfo entry (if any), validate it by trying to connect to
+ * it. Break out of the loop with first entry we can connect with. */
+ for (next = servinfo; next != NULL; next = next->ai_next) {
+ /* We're only interested in IPv4 or IPv6 entries */
+ if (next->ai_family == AF_INET || next->ai_family == AF_INET6) {
+ sfd = socket(next->ai_family, next->ai_socktype, next->ai_protocol);
+ if (sfd == -1)
+ continue;
+
+ if (connect(sfd, next->ai_addr, next->ai_addrlen) == -1) {
+ close(sfd);
+ continue;
+ }
+
+ /* Connection established. Use this entry. */
+ close(sfd);
+ break;
+ }
+ }
+
+ /* Could not connect using any entry returned by getaddrinfo() */
+ if (next == NULL) {
+ freeaddrinfo(servinfo);
+ return 0;
+ }
+
+ /* Update addr with the entry we could connect with */
+ addr->af = next->ai_family;
+ switch (next->ai_family) {
+ case AF_INET:
+ addr->u.v4.s_addr = (*(struct sockaddr_in *)next->ai_addr).sin_addr.s_addr;
+ break;
+
+#ifdef CONFIG_IPV6
+ case AF_INET6:
+ os_memcpy(addr->u.v6.s6_addr, &(*(struct sockaddr_in6 *)next->ai_addr).sin6_addr,
+ sizeof(struct in6_addr));
+ break;
+#endif /* CONFIG_IPV6 */
+ default:
+ return 0;
+ }
+
+ freeaddrinfo(servinfo);
+ return 1;
+}
+
const char * hostapd_ip_txt(const struct hostapd_ip_addr *addr, char *buf,
size_t buflen)
{
diff --git a/src/utils/ip_addr.h b/src/utils/ip_addr.h
index 0670411cc..25d69b544 100644
--- a/src/utils/ip_addr.h
+++ b/src/utils/ip_addr.h
@@ -24,4 +24,5 @@ const char * hostapd_ip_txt(const struct hostapd_ip_addr *addr, char *buf,
size_t buflen);
int hostapd_parse_ip_addr(const char *txt, struct hostapd_ip_addr *addr);
+int resolve_fqdn(const char *fqdn_addr, struct hostapd_ip_addr *addr);
#endif /* IP_ADDR_H */
--
2.33.0
More information about the Hostap
mailing list