]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
RADIUS: Simplify IPv4/IPv6 socket handling in client
authorJouni Malinen <j@w1.fi>
Sun, 25 Feb 2024 15:49:40 +0000 (17:49 +0200)
committerJouni Malinen <j@w1.fi>
Sun, 25 Feb 2024 16:10:05 +0000 (18:10 +0200)
There is only one connection in use in parallel to a RADIUS
authentication server (and similarly to a RADIUS accounting server). As
such, there is not really any need to maintain separate open IPv4 and
IPv6 sockets. Instead, open the socket for the appropriate IP version
only when actually connecting to a specific server.

Signed-off-by: Jouni Malinen <j@w1.fi>
src/radius/radius_client.c

index 17d05465747334f4e1c3bd10a57d619793192bf9..68e6d23d397e37f012078ba83cc401a2c97a6bdb 100644 (file)
@@ -168,26 +168,6 @@ struct radius_client_data {
         */
        struct hostapd_radius_servers *conf;
 
-       /**
-        * auth_serv_sock - IPv4 socket for RADIUS authentication messages
-        */
-       int auth_serv_sock;
-
-       /**
-        * acct_serv_sock - IPv4 socket for RADIUS accounting messages
-        */
-       int acct_serv_sock;
-
-       /**
-        * auth_serv_sock6 - IPv6 socket for RADIUS authentication messages
-        */
-       int auth_serv_sock6;
-
-       /**
-        * acct_serv_sock6 - IPv6 socket for RADIUS accounting messages
-        */
-       int acct_serv_sock6;
-
        /**
         * auth_sock - Currently used socket for RADIUS authentication server
         */
@@ -715,6 +695,42 @@ static void radius_client_list_add(struct radius_client_data *radius,
 }
 
 
+static int radius_client_disable_pmtu_discovery(int s)
+{
+       int r = -1;
+#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
+       /* Turn off Path MTU discovery on IPv4/UDP sockets. */
+       int action = IP_PMTUDISC_DONT;
+       r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action,
+                      sizeof(action));
+       if (r == -1)
+               wpa_printf(MSG_ERROR, "RADIUS: Failed to set IP_MTU_DISCOVER: %s",
+                          strerror(errno));
+#endif
+       return r;
+}
+
+
+static void radius_close_auth_socket(struct radius_client_data *radius)
+{
+       if (radius->auth_sock >= 0) {
+               eloop_unregister_read_sock(radius->auth_sock);
+               close(radius->auth_sock);
+               radius->auth_sock = -1;
+       }
+}
+
+
+static void radius_close_acct_socket(struct radius_client_data *radius)
+{
+       if (radius->acct_sock >= 0) {
+               eloop_unregister_read_sock(radius->acct_sock);
+               close(radius->acct_sock);
+               radius->acct_sock = -1;
+       }
+}
+
+
 /**
  * radius_client_send - Send a RADIUS request
  * @radius: RADIUS client context from radius_client_init()
@@ -1076,14 +1092,9 @@ radius_change_server(struct radius_client_data *radius,
        struct sockaddr *addr, *cl_addr;
        socklen_t addrlen, claddrlen;
        char abuf[50];
-       int sock = auth ? radius->auth_serv_sock : radius->acct_serv_sock;
-       int sock6 = auth ? radius->auth_serv_sock6 : radius->acct_serv_sock6;
        int sel_sock;
        struct radius_msg_list *entry;
        struct hostapd_radius_servers *conf = radius->conf;
-       struct sockaddr_in disconnect_addr = {
-               .sin_family = AF_UNSPEC,
-       };
 
        hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
                       HOSTAPD_LEVEL_INFO,
@@ -1142,7 +1153,9 @@ radius_change_server(struct radius_client_data *radius,
                serv.sin_port = htons(nserv->port);
                addr = (struct sockaddr *) &serv;
                addrlen = sizeof(serv);
-               sel_sock = sock;
+               sel_sock = socket(PF_INET, SOCK_DGRAM, 0);
+               if (sel_sock >= 0)
+                       radius_client_disable_pmtu_discovery(sel_sock);
                break;
 #ifdef CONFIG_IPV6
        case AF_INET6:
@@ -1153,7 +1166,7 @@ radius_change_server(struct radius_client_data *radius,
                serv6.sin6_port = htons(nserv->port);
                addr = (struct sockaddr *) &serv6;
                addrlen = sizeof(serv6);
-               sel_sock = sock6;
+               sel_sock = socket(PF_INET6, SOCK_DGRAM, 0);
                break;
 #endif /* CONFIG_IPV6 */
        default:
@@ -1162,16 +1175,11 @@ radius_change_server(struct radius_client_data *radius,
 
        if (sel_sock < 0) {
                wpa_printf(MSG_INFO,
-                          "RADIUS: No server socket available (af=%d sock=%d sock6=%d auth=%d",
-                          nserv->addr.af, sock, sock6, auth);
+                          "RADIUS: Failed to open server socket (af=%d auth=%d)",
+                          nserv->addr.af, auth);
                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,
@@ -1212,19 +1220,22 @@ radius_change_server(struct radius_client_data *radius,
                        break;
 #endif /* CONFIG_IPV6 */
                default:
+                       close(sel_sock);
                        return -1;
                }
 
                if (bind(sel_sock, cl_addr, claddrlen) < 0) {
                        wpa_printf(MSG_INFO, "bind[radius]: %s",
                                   strerror(errno));
-                       return -1;
+                       close(sel_sock);
+                       return -2;
                }
        }
 
        if (connect(sel_sock, addr, addrlen) < 0) {
                wpa_printf(MSG_INFO, "connect[radius]: %s", strerror(errno));
-               return -1;
+               close(sel_sock);
+               return -2;
        }
 
 #ifndef CONFIG_NATIVE_WINDOWS
@@ -1254,10 +1265,17 @@ radius_change_server(struct radius_client_data *radius,
        }
 #endif /* CONFIG_NATIVE_WINDOWS */
 
-       if (auth)
+       if (auth) {
+               radius_close_auth_socket(radius);
                radius->auth_sock = sel_sock;
-       else
+       } else {
+               radius_close_acct_socket(radius);
                radius->acct_sock = sel_sock;
+       }
+
+       eloop_register_read_sock(sel_sock, radius_client_receive, radius,
+                                auth ? (void *) RADIUS_AUTH :
+                                (void *) RADIUS_ACCT);
 
        return 0;
 }
@@ -1300,165 +1318,17 @@ static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx)
 }
 
 
-static int radius_client_disable_pmtu_discovery(int s)
-{
-       int r = -1;
-#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
-       /* Turn off Path MTU discovery on IPv4/UDP sockets. */
-       int action = IP_PMTUDISC_DONT;
-       r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action,
-                      sizeof(action));
-       if (r == -1)
-               wpa_printf(MSG_ERROR, "RADIUS: Failed to set IP_MTU_DISCOVER: %s",
-                          strerror(errno));
-#endif
-       return r;
-}
-
-
-static void radius_close_auth_sockets(struct radius_client_data *radius)
-{
-       radius->auth_sock = -1;
-
-       if (radius->auth_serv_sock >= 0) {
-               eloop_unregister_read_sock(radius->auth_serv_sock);
-               close(radius->auth_serv_sock);
-               radius->auth_serv_sock = -1;
-       }
-#ifdef CONFIG_IPV6
-       if (radius->auth_serv_sock6 >= 0) {
-               eloop_unregister_read_sock(radius->auth_serv_sock6);
-               close(radius->auth_serv_sock6);
-               radius->auth_serv_sock6 = -1;
-       }
-#endif /* CONFIG_IPV6 */
-}
-
-
-static void radius_close_acct_sockets(struct radius_client_data *radius)
-{
-       radius->acct_sock = -1;
-
-       if (radius->acct_serv_sock >= 0) {
-               eloop_unregister_read_sock(radius->acct_serv_sock);
-               close(radius->acct_serv_sock);
-               radius->acct_serv_sock = -1;
-       }
-#ifdef CONFIG_IPV6
-       if (radius->acct_serv_sock6 >= 0) {
-               eloop_unregister_read_sock(radius->acct_serv_sock6);
-               close(radius->acct_serv_sock6);
-               radius->acct_serv_sock6 = -1;
-       }
-#endif /* CONFIG_IPV6 */
-}
-
-
 static int radius_client_init_auth(struct radius_client_data *radius)
 {
-       struct hostapd_radius_servers *conf = radius->conf;
-       int ok = 0;
-
-       radius_close_auth_sockets(radius);
-
-       radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
-       if (radius->auth_serv_sock < 0)
-               wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s",
-                          strerror(errno));
-       else {
-               radius_client_disable_pmtu_discovery(radius->auth_serv_sock);
-               ok++;
-       }
-
-#ifdef CONFIG_IPV6
-       radius->auth_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
-       if (radius->auth_serv_sock6 < 0)
-               wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET6,SOCK_DGRAM]: %s",
-                          strerror(errno));
-       else
-               ok++;
-#endif /* CONFIG_IPV6 */
-
-       if (ok == 0)
-               return -1;
-
-       radius_change_server(radius, conf->auth_server, NULL, 1);
-
-       if (radius->auth_serv_sock >= 0 &&
-           eloop_register_read_sock(radius->auth_serv_sock,
-                                    radius_client_receive, radius,
-                                    (void *) RADIUS_AUTH)) {
-               wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server");
-               radius_close_auth_sockets(radius);
-               return -1;
-       }
-
-#ifdef CONFIG_IPV6
-       if (radius->auth_serv_sock6 >= 0 &&
-           eloop_register_read_sock(radius->auth_serv_sock6,
-                                    radius_client_receive, radius,
-                                    (void *) RADIUS_AUTH)) {
-               wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server");
-               radius_close_auth_sockets(radius);
-               return -1;
-       }
-#endif /* CONFIG_IPV6 */
-
-       return 0;
+       radius_close_auth_socket(radius);
+       return radius_change_server(radius, radius->conf->auth_server, NULL, 1);
 }
 
 
 static int radius_client_init_acct(struct radius_client_data *radius)
 {
-       struct hostapd_radius_servers *conf = radius->conf;
-       int ok = 0;
-
-       radius_close_acct_sockets(radius);
-
-       radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
-       if (radius->acct_serv_sock < 0)
-               wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s",
-                          strerror(errno));
-       else {
-               radius_client_disable_pmtu_discovery(radius->acct_serv_sock);
-               ok++;
-       }
-
-#ifdef CONFIG_IPV6
-       radius->acct_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
-       if (radius->acct_serv_sock6 < 0)
-               wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET6,SOCK_DGRAM]: %s",
-                          strerror(errno));
-       else
-               ok++;
-#endif /* CONFIG_IPV6 */
-
-       if (ok == 0)
-               return -1;
-
-       radius_change_server(radius, conf->acct_server, NULL, 0);
-
-       if (radius->acct_serv_sock >= 0 &&
-           eloop_register_read_sock(radius->acct_serv_sock,
-                                    radius_client_receive, radius,
-                                    (void *) RADIUS_ACCT)) {
-               wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server");
-               radius_close_acct_sockets(radius);
-               return -1;
-       }
-
-#ifdef CONFIG_IPV6
-       if (radius->acct_serv_sock6 >= 0 &&
-           eloop_register_read_sock(radius->acct_serv_sock6,
-                                    radius_client_receive, radius,
-                                    (void *) RADIUS_ACCT)) {
-               wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server");
-               radius_close_acct_sockets(radius);
-               return -1;
-       }
-#endif /* CONFIG_IPV6 */
-
-       return 0;
+       radius_close_acct_socket(radius);
+       return radius_change_server(radius, radius->conf->acct_server, NULL, 0);
 }
 
 
@@ -1483,16 +1353,14 @@ radius_client_init(void *ctx, struct hostapd_radius_servers *conf)
 
        radius->ctx = ctx;
        radius->conf = conf;
-       radius->auth_serv_sock = radius->acct_serv_sock =
-               radius->auth_serv_sock6 = radius->acct_serv_sock6 =
-               radius->auth_sock = radius->acct_sock = -1;
+       radius->auth_sock = radius->acct_sock = -1;
 
-       if (conf->auth_server && radius_client_init_auth(radius)) {
+       if (conf->auth_server && radius_client_init_auth(radius) == -1) {
                radius_client_deinit(radius);
                return NULL;
        }
 
-       if (conf->acct_server && radius_client_init_acct(radius)) {
+       if (conf->acct_server && radius_client_init_acct(radius) == -1) {
                radius_client_deinit(radius);
                return NULL;
        }
@@ -1515,8 +1383,8 @@ void radius_client_deinit(struct radius_client_data *radius)
        if (!radius)
                return;
 
-       radius_close_auth_sockets(radius);
-       radius_close_acct_sockets(radius);
+       radius_close_auth_socket(radius);
+       radius_close_acct_socket(radius);
 
        eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL);