From b697f37ad75ef7f248be0d135550159eede3284b Mon Sep 17 00:00:00 2001 From: Roy Marples Date: Fri, 16 May 2025 13:12:22 +0100 Subject: [PATCH] IPv6: store the destination address We need to match this address on BSD and Illumos as it might be the gateway address for a route to find the interface it belongs to. --- src/if-bsd.c | 8 +++++++- src/if-linux.c | 19 +++++++++-------- src/if-sun.c | 8 +++++++- src/if.c | 21 +++++++++++-------- src/ipv6.c | 56 +++++++++++++++++++++++++++++++++++++++++--------- src/ipv6.h | 6 +++++- 6 files changed, 88 insertions(+), 30 deletions(-) diff --git a/src/if-bsd.c b/src/if-bsd.c index bb9c223a..1177ee35 100644 --- a/src/if-bsd.c +++ b/src/if-bsd.c @@ -665,6 +665,8 @@ if_findsa(struct dhcpcd_ctx *ctx, const struct sockaddr *sa) return if_findindex(ctx->ifaces, scope); if ((ia = ipv6_findmaskaddr(ctx, &sin->sin6_addr))) return ia->iface; + if ((ia = ipv6_finddstaddr(ctx, &sin->sin6_addr))) + return ia->iface; break; } #endif @@ -1508,12 +1510,15 @@ if_ifa(struct dhcpcd_ctx *ctx, const struct ifa_msghdr *ifam) case AF_INET6: { struct in6_addr addr6, mask6; + const struct in6_addr *dstaddr6; const struct sockaddr_in6 *sin6; sin6 = (const void *)rti_info[RTAX_IFA]; addr6 = sin6->sin6_addr; sin6 = (const void *)rti_info[RTAX_NETMASK]; mask6 = sin6->sin6_addr; + sin6 = (const void *)rti_info[RTAX_BRD]; + dstaddr6 = sin6 ? &sin6->sin6_addr : NULL; /* * If the address was deleted, lets check if it's @@ -1539,7 +1544,8 @@ if_ifa(struct dhcpcd_ctx *ctx, const struct ifa_msghdr *ifam) #endif ipv6_handleifa(ctx, ifam->ifam_type, NULL, - ifp->name, &addr6, ipv6_prefixlen(&mask6), flags, pid); + ifp->name, &addr6, ipv6_prefixlen(&mask6), + dstaddr6, flags, pid); break; } #endif diff --git a/src/if-linux.c b/src/if-linux.c index 96d1e50b..7e0e3c72 100644 --- a/src/if-linux.c +++ b/src/if-linux.c @@ -876,7 +876,7 @@ link_addr(struct dhcpcd_ctx *ctx, struct interface *ifp, struct nlmsghdr *nlm) int ret; #endif #ifdef INET6 - struct in6_addr *local6 = NULL, *address6 = NULL; + struct in6_addr *local6 = NULL, *addr6 = NULL, *dstaddr6 = NULL; int flags; #endif @@ -957,7 +957,10 @@ link_addr(struct dhcpcd_ctx *ctx, struct interface *ifp, struct nlmsghdr *nlm) for (; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) { switch (rta->rta_type) { case IFA_ADDRESS: - address6 = (struct in6_addr *)RTA_DATA(rta); + addr6 = (struct in6_addr *)RTA_DATA(rta); + break; + case IFA_BROADCAST: + dstaddr6 = (struct in6_addr *)RTA_DATA(rta); break; case IFA_LOCAL: local6 = (struct in6_addr *)RTA_DATA(rta); @@ -965,13 +968,13 @@ link_addr(struct dhcpcd_ctx *ctx, struct interface *ifp, struct nlmsghdr *nlm) } } if (local6 != NULL) - address6 = local6; - if (address6 == NULL) + addr6 = local6; + if (addr6 == NULL) break; /* should be impossible */ /* Validate RTM_DELADDR really means address deleted * and anything else really means address exists. */ - flags = if_addrflags6(ifp, address6, NULL); + flags = if_addrflags6(ifp, addr6, NULL); if (nlm->nlmsg_type == RTM_DELADDR) { if (flags != -1) break; @@ -981,8 +984,8 @@ link_addr(struct dhcpcd_ctx *ctx, struct interface *ifp, struct nlmsghdr *nlm) } ipv6_handleifa(ctx, nlm->nlmsg_type, NULL, ifp->name, - address6, ifa->ifa_prefixlen, ifa->ifa_flags, - (pid_t)nlm->nlmsg_pid); + addr6, ifa->ifa_prefixlen, dstaddr6, + ifa->ifa_flags, (pid_t)nlm->nlmsg_pid); break; #endif } @@ -1143,7 +1146,7 @@ link_netlink(struct dhcpcd_ctx *ctx, void *arg, struct nlmsghdr *nlm) } if (mtu != NULL) - ifp->mtu = *(unsigned int *)RTA_DATA(mtu); + ifp->mtu = (int)*(unsigned int *)RTA_DATA(mtu); /* Re-read hardware address and friends */ if (!(ifi->ifi_flags & IFF_UP)) { diff --git a/src/if-sun.c b/src/if-sun.c index 6dc4a77b..24ef5b58 100644 --- a/src/if-sun.c +++ b/src/if-sun.c @@ -539,6 +539,8 @@ if_findsa(struct dhcpcd_ctx *ctx, const struct sockaddr *sa) sin = (const void *)sa; if ((ia = ipv6_findmaskaddr(ctx, &sin->sin6_addr))) return ia->iface; + if ((ia = ipv6_finddstaddr(ctx, &sin->sin6_addr))) + return ia->iface; break; } #endif @@ -1004,12 +1006,15 @@ if_ifa(struct dhcpcd_ctx *ctx, const struct ifa_msghdr *ifam) case AF_INET6: { struct in6_addr addr6, mask6; + const struct in6_addr *dstaddr6; const struct sockaddr_in6 *sin6; sin6 = (const void *)rti_info[RTAX_IFA]; addr6 = sin6->sin6_addr; sin6 = (const void *)rti_info[RTAX_NETMASK]; mask6 = sin6->sin6_addr; + sin6 = (const void *)rti_info[RTAX_BRD]; + dstaddr6 = sin6 ? &sin6->sin6_addr : NULL; if (ifam->ifam_type == RTM_DELADDR) { struct ipv6_addr *ia; @@ -1029,7 +1034,8 @@ if_ifa(struct dhcpcd_ctx *ctx, const struct ifa_msghdr *ifam) ipv6_handleifa(ctx, ifam->ifam_type == RTM_CHGADDR ? RTM_NEWADDR : ifam->ifam_type, - NULL, ifalias, &addr6, ipv6_prefixlen(&mask6), flags, 0); + NULL, ifalias, &addr6, ipv6_prefixlen(&mask6), + dstaddr6, flags, 0); break; } #endif diff --git a/src/if.c b/src/if.c index a74c18c4..9b5ac2be 100644 --- a/src/if.c +++ b/src/if.c @@ -269,7 +269,7 @@ if_learnaddrs(struct dhcpcd_ctx *ctx, struct if_head *ifs, const struct sockaddr_in *addr, *net, *brd; #endif #ifdef INET6 - struct sockaddr_in6 *sin6, *net6; + struct sockaddr_in6 *addr6, *net6, *dstaddr6; #endif int addrflags; @@ -313,24 +313,25 @@ if_learnaddrs(struct dhcpcd_ctx *ctx, struct if_head *ifs, #endif #ifdef INET6 case AF_INET6: - sin6 = (void *)ifa->ifa_addr; + addr6 = (void *)ifa->ifa_addr; + dstaddr6 = (void *)ifa->ifa_dstaddr; net6 = (void *)ifa->ifa_netmask; #ifdef __KAME__ - if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) + if (IN6_IS_ADDR_LINKLOCAL(&addr6->sin6_addr)) /* Remove the scope from the address */ - sin6->sin6_addr.s6_addr[2] = - sin6->sin6_addr.s6_addr[3] = '\0'; + addr6->sin6_addr.s6_addr[2] = + addr6->sin6_addr.s6_addr[3] = '\0'; #endif #ifndef HAVE_IFADDRS_ADDRFLAGS - addrflags = if_addrflags6(ifp, &sin6->sin6_addr, + addrflags = if_addrflags6(ifp, &addr6->sin6_addr, ifa->ifa_name); if (addrflags == -1) { if (errno != EEXIST && errno != EADDRNOTAVAIL) { char dbuf[INET6_ADDRSTRLEN]; const char *dbp; - dbp = inet_ntop(AF_INET6, &sin6->sin6_addr, + dbp = inet_ntop(AF_INET6, &addr6->sin6_addr, dbuf, sizeof(dbuf)); logerr("%s: if_addrflags6: %s%%%s", __func__, dbp, ifp->name); @@ -339,8 +340,10 @@ if_learnaddrs(struct dhcpcd_ctx *ctx, struct if_head *ifs, } #endif ipv6_handleifa(ctx, RTM_NEWADDR, ifs, - ifa->ifa_name, &sin6->sin6_addr, - ipv6_prefixlen(&net6->sin6_addr), addrflags, 0); + ifa->ifa_name, &addr6->sin6_addr, + ipv6_prefixlen(&net6->sin6_addr), + dstaddr6 ? &dstaddr6->sin6_addr : NULL, + addrflags, 0); break; #endif } diff --git a/src/ipv6.c b/src/ipv6.c index 107e5988..9261f9a4 100644 --- a/src/ipv6.c +++ b/src/ipv6.c @@ -597,7 +597,7 @@ ipv6_checkaddrflags(void *arg) /* Simulate the kernel announcing the new address. */ ipv6_handleifa(ia->iface->ctx, RTM_NEWADDR, ia->iface->ctx->ifaces, ia->iface->name, - &ia->addr, ia->prefix_len, flags, 0); + &ia->addr, ia->prefix_len, ia->dstaddr, flags, 0); } else { /* Still tentative? Check again in a bit. */ eloop_timeout_add_msec(ia->iface->ctx->eloop, @@ -1108,7 +1108,8 @@ ipv6_anyglobal(struct interface *sifp) void ipv6_handleifa(struct dhcpcd_ctx *ctx, int cmd, struct if_head *ifs, const char *ifname, - const struct in6_addr *addr, uint8_t prefix_len, int addrflags, pid_t pid) + const struct in6_addr *addr, uint8_t prefix_len, + const struct in6_addr *dstaddr, int addrflags, pid_t pid) { struct interface *ifp; struct ipv6_state *state; @@ -1132,13 +1133,15 @@ ipv6_handleifa(struct dhcpcd_ctx *ctx, #endif #if 0 - char dbuf[INET6_ADDRSTRLEN]; - const char *dbp; - - dbp = inet_ntop(AF_INET6, &addr->s6_addr, - dbuf, INET6_ADDRSTRLEN); - loginfox("%s: cmd %d addr %s addrflags %d", - ifname, cmd, dbp, addrflags); + char abuf[INET6_ADDRSTRLEN], dbuf[INET6_ADDRSTRLEN]; + const char *abp, *dbp; + + abp = inet_ntop(AF_INET6, &addr->s6_addr, abuf, sizeof(abuf)); + dbp = dstaddr ? + inet_ntop(AF_INET6, &dstaddr->s6_addr, dbuf, sizeof(dbuf)) + : "::"; + loginfox("%s: cmd %d addr %s dstaddr %s addrflags %d", + ifname, cmd, abp, dbp, addrflags); #endif if (ifs == NULL) @@ -1199,6 +1202,7 @@ ipv6_handleifa(struct dhcpcd_ctx *ctx, ia->addr_flags = addrflags; TAILQ_INSERT_TAIL(&state->addrs, ia, next); } + ia->dstaddr = dstaddr ? *dstaddr : in6addr_any; ia->flags &= ~IPV6_AF_STALE; #ifdef IPV6_MANAGETEMPADDR if (ia->addr_flags & IN6_IFF_TEMPORARY) @@ -1338,6 +1342,37 @@ ipv6_findmaskaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr) return NULL; } + +static struct ipv6_addr * +ipv6_iffinddstaddr(const struct interface *ifp, const struct in6_addr *addr) +{ + struct ipv6_state *state; + struct ipv6_addr *ap; + + state = IPV6_STATE(ifp); + if (state) { + TAILQ_FOREACH(ap, &state->addrs, next) { + if (IN6_ARE_ADDR_EQUAL(&ap->dstaddr, addr)) + return ap; + } + } + return NULL; +} + +struct ipv6_addr * +ipv6_finddstaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr) +{ + struct interface *ifp; + struct ipv6_addr *ap; + + TAILQ_FOREACH(ifp, ctx->ifaces, next) { + ap = ipv6_iffinddstaddr(ifp, addr); + if (ap != NULL) + return ap; + } + return NULL; +} + int ipv6_addlinklocalcallback(struct interface *ifp, void (*callback)(void *), void *arg) @@ -2145,7 +2180,8 @@ ipv6_deletestaleaddrs(struct interface *ifp) if (ia->flags & IPV6_AF_STALE) ipv6_handleifa(ifp->ctx, RTM_DELADDR, ifp->ctx->ifaces, ifp->name, - &ia->addr, ia->prefix_len, 0, getpid()); + &ia->addr, ia->prefix_len, + &ia->dstaddr, 0, getpid()); } } diff --git a/src/ipv6.h b/src/ipv6.h index 0e89935e..fd9f4f23 100644 --- a/src/ipv6.h +++ b/src/ipv6.h @@ -170,6 +170,7 @@ struct ipv6_addr { struct timespec created; struct timespec acquired; struct in6_addr addr; + struct in6_addr dstaddr; int addr_flags; unsigned int flags; char saddr[INET6_ADDRSTRLEN]; @@ -261,7 +262,8 @@ void ipv6_deleteaddr(struct ipv6_addr *); void ipv6_freedrop_addrs(struct ipv6_addrhead *, int, unsigned int, const struct interface *); void ipv6_handleifa(struct dhcpcd_ctx *ctx, int, struct if_head *, - const char *, const struct in6_addr *, uint8_t, int, pid_t); + const char *, const struct in6_addr *, uint8_t, + const struct in6_addr *, int, pid_t); int ipv6_handleifa_addrs(int, struct ipv6_addrhead *, const struct ipv6_addr *, pid_t); struct ipv6_addr *ipv6_iffindaddr(struct interface *, @@ -274,6 +276,8 @@ struct ipv6_addr *ipv6_findaddr(struct dhcpcd_ctx *, const struct in6_addr *, unsigned int); struct ipv6_addr *ipv6_findmaskaddr(struct dhcpcd_ctx *, const struct in6_addr *); +struct ipv6_addr *ipv6_finddstaddr(struct dhcpcd_ctx *, + const struct in6_addr *); #define ipv6_linklocal(ifp) ipv6_iffindaddr((ifp), NULL, IN6_IFF_NOTUSEABLE) int ipv6_addlinklocalcallback(struct interface *, void (*)(void *), void *); void ipv6_setscope(struct sockaddr_in6 *, unsigned int); -- 2.47.3