]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
IPv6: store the destination address
authorRoy Marples <roy@marples.name>
Fri, 16 May 2025 12:12:22 +0000 (13:12 +0100)
committerRoy Marples <roy@marples.name>
Fri, 16 May 2025 12:12:22 +0000 (13:12 +0100)
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
src/if-linux.c
src/if-sun.c
src/if.c
src/ipv6.c
src/ipv6.h

index bb9c223a84f4fca58a2dbd7e236c42374e98c8e9..1177ee358ac2dffd83e121b7079ab9186ef3b48b 100644 (file)
@@ -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
index 96d1e50b9a5be157e4b5a7d6144bf2396c751a61..7e0e3c7203710a24b33eaf5eceefd67be3e0f1fa 100644 (file)
@@ -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)) {
index 6dc4a77bba76cc05ba60be54774ae784161bf980..24ef5b58d087510444b5223206970b8e2195f4d5 100644 (file)
@@ -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
index a74c18c40de734db6e71c9f310ef19b874330ccb..9b5ac2be2c918b0ed68426c0614ef79287277cb5 100644 (file)
--- 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
                }
index 107e5988f8072d7b49db476bc5715f9c56bdd2c7..9261f9a48b1cdbb9296190a0bc4b76502fca2db6 100644 (file)
@@ -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());
        }
 }
 
index 0e89935e8cd339f8a317c0ec9a91c0d064e21496..fd9f4f2338c697cd0d4e8ca3ab80e115b3a89693 100644 (file)
@@ -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);