This patch adds support to configure Fully Qualified Domain Names (FQDN) for authentication and accounting server addresses. Signed-off-by: Magnus Malm <magnusmalm@xxxxxxxxx> --- 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 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap