On Sat, Mar 07, 2026 at 01:41:57PM -0500, Jon Maloy wrote: > nl_addr_get() was not setting the prefix_len output parameter for > IPv6 addresses, only for IPv4. This meant callers always got 0 for > IPv6, forcing them to use a hardcoded default (64). > > Fix by assigning *prefix_len even in the IPv6 case. > > We also add another functional change. We now check for if an AF_INET > address is link local, in which case we have to skip it. Although it > is conventional to set the scope of such addresses to RT_SCOPE_LINK, > this is not stated in any RFC, and we cannot trust it to have been set > correctly by the user, just as we cannot trust it to have been set > correctly for any other AF_INET address. We therefore add this check > explicitly on the address itself. > > Signed-off-by: Jon Maloy > > --- > v2: - Simplified according to feedback from S. Brivio > - Added test for AF_INET link local property > v3: - Corrected claim about convention for IPv4 link local address > scope in commit log. > --- > netlink.c | 17 +++++++---------- > 1 file changed, 7 insertions(+), 10 deletions(-) > > diff --git a/netlink.c b/netlink.c > index 82a2f0c..f0e8fa7 100644 > --- a/netlink.c > +++ b/netlink.c > @@ -752,7 +752,7 @@ int nl_addr_set_ll_nodad(int s, unsigned int ifi) > * @ifi: Interface index in outer network namespace > * @af: Address family > * @addr: Global address to fill > - * @prefix_len: Mask or prefix length, to fill (for IPv4) > + * @prefix_len: Mask or prefix length, to fill > * @addr_l: Link-scoped address to fill (for IPv6) > * > * Return: 0 on success, negative error code on failure > @@ -777,6 +777,7 @@ int nl_addr_get(int s, unsigned int ifi, sa_family_t af, > nl_foreach_oftype(nh, status, s, buf, seq, RTM_NEWADDR) { > struct ifaddrmsg *ifa = (struct ifaddrmsg *)NLMSG_DATA(nh); > struct rtattr *rta; > + bool link_local; > size_t na; > > if (ifa->ifa_index != ifi || ifa->ifa_flags & IFA_F_DEPRECATED) > @@ -788,18 +789,14 @@ int nl_addr_get(int s, unsigned int ifi, sa_family_t af, > (af == AF_INET6 && rta->rta_type != IFA_ADDRESS)) > continue; > > - if (af == AF_INET && ifa->ifa_prefixlen > prefix_max) { > - memcpy(addr, RTA_DATA(rta), RTA_PAYLOAD(rta)); > + link_local = (af == AF_INET6) ? > + ifa->ifa_scope >= RT_SCOPE_LINK : > + IN4_IS_ADDR_LINKLOCAL(RTA_DATA(rta)); Is ifa->ifa_scope not populatedcorrectly for IPv4 link local addresses? > > - prefix_max = *prefix_len = ifa->ifa_prefixlen; > - } else if (af == AF_INET6 && addr && > - ifa->ifa_scope < RT_SCOPE_LINK && > - ifa->ifa_prefixlen > prefix_max) { > + if (ifa->ifa_prefixlen > prefix_max && !link_local) { > memcpy(addr, RTA_DATA(rta), RTA_PAYLOAD(rta)); > - > - prefix_max = ifa->ifa_prefixlen; > + prefix_max = *prefix_len = ifa->ifa_prefixlen; > } > - > if (addr_l && > af == AF_INET6 && ifa->ifa_scope == RT_SCOPE_LINK && > ifa->ifa_prefixlen > prefix_max_ll) { > -- > 2.52.0 > -- David Gibson (he or they) | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you, not the other way | around. http://www.ozlabs.org/~dgibson