]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
add fr_ipaddr_get_scope_id() function and use it in FD bios
authorAlan T. DeKok <aland@freeradius.org>
Tue, 2 Apr 2024 20:56:30 +0000 (16:56 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Tue, 2 Apr 2024 20:57:04 +0000 (16:57 -0400)
src/lib/bio/fd.c
src/lib/util/inet.c
src/lib/util/inet.h

index 26c9ae910d9da9551c70ba1ca102f7a9847fe4d2..0de587887903f000ff585244a239e25735bbb00d 100644 (file)
@@ -665,7 +665,12 @@ int fr_bio_fd_socket_name(fr_bio_fd_t *my)
                return -1;
        }
 
-       return fr_ipaddr_from_sockaddr(&my->info.socket.inet.src_ipaddr, &my->info.socket.inet.src_port, &salocal, salen);
+       if (fr_ipaddr_from_sockaddr(&my->info.socket.inet.src_ipaddr, &my->info.socket.inet.src_port, &salocal, salen) < 0) return -1;
+
+       fr_ipaddr_get_scope_id(&my->info.socket.inet.src_ipaddr);
+       my->info.socket.inet.ifindex = my->info.socket.inet.src_ipaddr.scope_id;
+
+       return 0;
 }
 
 
index d1ceb899cbed15859796a5916e855e90e865e58f..c1f206feed1046511c5d7eb58c2cf0c853f7418d 100644 (file)
@@ -1469,6 +1469,50 @@ int fr_ipaddr_from_sockaddr(fr_ipaddr_t *ipaddr, uint16_t *port,
        return 0;
 }
 
+void  fr_ipaddr_get_scope_id(fr_ipaddr_t *ipaddr)
+{
+       struct ifaddrs *list = NULL;
+       struct ifaddrs *i;
+
+       /*
+        *      This should be set already for IPv6.  We should only need to do this for IPv4.
+        */
+       if (ipaddr->scope_id != 0) return;
+
+       /*
+        *      Bind manually to an IP used by the named interface.
+        */
+       if (getifaddrs(&list) < 0) return;
+
+       for (i = list; i != NULL; i = i->ifa_next) {
+               fr_ipaddr_t my_ipaddr;
+
+               if (!i->ifa_addr || !i->ifa_name || (ipaddr->af != i->ifa_addr->sa_family)) continue;
+
+               fr_ipaddr_from_sockaddr(&my_ipaddr, NULL,
+                                       (struct sockaddr_storage *)i->ifa_addr, sizeof(struct sockaddr_in6));
+               my_ipaddr.scope_id = 0;
+
+               /*
+                *      my_ipaddr will have a scope_id, but the input
+                *      ipaddr won't have one.  We therefore set the
+                *      local one to zero, so that we can do correct
+                *      IP address comparisons.
+                *
+                *      If the comparison succeeds, then we return
+                *      both the interface name, and we update the
+                *      input ipaddr with the correct scope_id.
+                */
+               if (fr_ipaddr_cmp(ipaddr, &my_ipaddr) == 0) {
+                       ipaddr->scope_id = if_nametoindex(i->ifa_name);
+                       break;
+               }
+       }
+
+       freeifaddrs(list);
+}
+
+
 char *fr_ipaddr_to_interface(TALLOC_CTX *ctx, fr_ipaddr_t *ipaddr)
 {
        struct ifaddrs *list = NULL;
index aed9dddff499e341994a2db7d3b8430c9cef4513..01d922415ad0b7d42f9cc1999bf95cc5e16c6056 100644 (file)
@@ -145,6 +145,7 @@ int fr_ipaddr_from_ifindex(fr_ipaddr_t *out, int fd, int af, int ifindex);
 #endif
 
 char   *fr_ipaddr_to_interface(TALLOC_CTX *ctx, fr_ipaddr_t *ipaddr);
+void   fr_ipaddr_get_scope_id(fr_ipaddr_t *ipaddr);
 int    fr_interface_to_ipaddr(char const *interface, fr_ipaddr_t *ipaddr, int af, bool link_local);
 
 int    fr_interface_to_ethernet(char const *interface, fr_ethernet_t *ethernet);