From: Alan T. DeKok Date: Tue, 2 Apr 2024 20:56:30 +0000 (-0400) Subject: add fr_ipaddr_get_scope_id() function and use it in FD bios X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b2dc5adbc693fb0fab1d6435e386fce24ab8554c;p=thirdparty%2Ffreeradius-server.git add fr_ipaddr_get_scope_id() function and use it in FD bios --- diff --git a/src/lib/bio/fd.c b/src/lib/bio/fd.c index 26c9ae910d9..0de58788790 100644 --- a/src/lib/bio/fd.c +++ b/src/lib/bio/fd.c @@ -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; } diff --git a/src/lib/util/inet.c b/src/lib/util/inet.c index d1ceb899cbe..c1f206feed1 100644 --- a/src/lib/util/inet.c +++ b/src/lib/util/inet.c @@ -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; diff --git a/src/lib/util/inet.h b/src/lib/util/inet.h index aed9dddff49..01d922415ad 100644 --- a/src/lib/util/inet.h +++ b/src/lib/util/inet.h @@ -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);