]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
ND: If a secondary router adds the same prefix, use it's address
authorRoy Marples <roy@marples.name>
Tue, 31 Mar 2020 21:33:25 +0000 (22:33 +0100)
committerRoy Marples <roy@marples.name>
Tue, 31 Mar 2020 21:33:25 +0000 (22:33 +0100)
With slaac private, it will generate a new address which would
be wrong.

src/ipv6.c
src/ipv6nd.c
src/ipv6nd.h

index 000db9840ca22b183a044e216dcc92c82b04f7a5..51b4c9b783049780ac3fc98b8423802ee05c2b5c 100644 (file)
@@ -1509,17 +1509,26 @@ struct ipv6_addr *
 ipv6_newaddr(struct interface *ifp, const struct in6_addr *addr,
     uint8_t prefix_len, unsigned int flags)
 {
-       struct ipv6_addr *ia;
+       struct ipv6_addr *ia, *iaf;
        char buf[INET6_ADDRSTRLEN];
        const char *cbp;
        bool tempaddr;
        int addr_flags;
 
+#ifdef IPV6_AF_TEMPORARY
+       tempaddr = flags & IPV6_AF_TEMPORARY;
+#else
+       tempaddr = false;
+#endif
+
        /* If adding a new DHCP / RA derived address, check current flags
         * from an existing address. */
-       ia = ipv6_iffindaddr(ifp, addr, 0);
-       if (ia != NULL) {
-               addr_flags = ia->addr_flags;
+       if (flags & IPV6_AF_AUTOCONF)
+               iaf = ipv6nd_iffindprefix(ifp, addr, prefix_len);
+       else
+               iaf = ipv6_iffindaddr(ifp, addr, 0);
+       if (iaf != NULL) {
+               addr_flags = iaf->addr_flags;
                flags |= IPV6_AF_ADDED;
        } else
                addr_flags = IN6_IFF_TENTATIVE;
@@ -1540,21 +1549,19 @@ ipv6_newaddr(struct interface *ifp, const struct in6_addr *addr,
        TAILQ_INIT(&ia->pd_pfxs);
 #endif
 
-#ifdef IPV6_AF_TEMPORARY
-       tempaddr = ia->flags & IPV6_AF_TEMPORARY;
-#else
-       tempaddr = false;
-#endif
-
        if (prefix_len == 128)
                goto makepfx;
        else if (ia->flags & IPV6_AF_AUTOCONF && !tempaddr) {
                ia->prefix = *addr;
-               ia->dadcounter = ipv6_makeaddr(&ia->addr, ifp,
-                                              &ia->prefix,
-                                              ia->prefix_len);
-               if (ia->dadcounter == -1)
-                       goto err;
+               if (iaf != NULL)
+                       memcpy(&ia->addr, &iaf->addr, sizeof(ia->addr));
+               else {
+                       ia->dadcounter = ipv6_makeaddr(&ia->addr, ifp,
+                                                      &ia->prefix,
+                                                      ia->prefix_len);
+                       if (ia->dadcounter == -1)
+                               goto err;
+               }
        } else if (ia->flags & IPV6_AF_RAPFX) {
                ia->prefix = *addr;
 #ifdef __sun
index ca5f4335636911b530cfd33ff2c3ac8e0e113487..81a80550cafdcb8652d04bfa9ca8942546a84e87 100644 (file)
@@ -746,6 +746,40 @@ ipv6nd_findaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr,
        return NULL;
 }
 
+static struct ipv6_addr *
+ipv6nd_rapfindprefix(struct ra *rap,
+    const struct in6_addr *pfx, uint8_t pfxlen)
+{
+       struct ipv6_addr *ia;
+
+       TAILQ_FOREACH(ia, &rap->addrs, next) {
+               if (ia->prefix_vltime == 0)
+                       continue;
+               if (ia->prefix_len == pfxlen &&
+                   IN6_ARE_ADDR_EQUAL(&ia->prefix, pfx))
+                       break;
+       }
+       return ia;
+}
+
+struct ipv6_addr *
+ipv6nd_iffindprefix(struct interface *ifp,
+    const struct in6_addr *pfx, uint8_t pfxlen)
+{
+       struct ra *rap;
+       struct ipv6_addr *ia;
+
+       ia = NULL;
+       TAILQ_FOREACH(rap, ifp->ctx->ra_routers, next) {
+               if (rap->iface != ifp)
+                       continue;
+               ia = ipv6nd_rapfindprefix(rap, pfx, pfxlen);
+               if (ia != NULL)
+                       break;
+       }
+       return ia;
+}
+
 static void
 ipv6nd_removefreedrop_ra(struct ra *rap, int remove_ra, int drop_ra)
 {
@@ -1229,10 +1263,8 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
                                logmessage(loglevel, "%s: pltime > vltime", ifp->name);
                                continue;
                        }
-                       TAILQ_FOREACH(ia, &rap->addrs, next)
-                               if (ia->prefix_len == pi.nd_opt_pi_prefix_len &&
-                                   IN6_ARE_ADDR_EQUAL(&ia->prefix, &pi_prefix))
-                                       break;
+                       ia = ipv6nd_rapfindprefix(rap,
+                           &pi_prefix, pi.nd_opt_pi_prefix_len);
                        if (ia == NULL) {
                                unsigned int flags;
 
index 0c85239d3b1ca7099a8a405cbb0f64ddb54c3994..bb14d7b34d59a82e24a396f1ea04123db20ad73e 100644 (file)
@@ -112,6 +112,8 @@ const struct ipv6_addr *ipv6nd_iffindaddr(const struct interface *ifp,
     const struct in6_addr *addr, unsigned int flags);
 struct ipv6_addr *ipv6nd_findaddr(struct dhcpcd_ctx *,
     const struct in6_addr *, unsigned int);
+struct ipv6_addr *ipv6nd_iffindprefix(struct interface *,
+    const struct in6_addr *, uint8_t);
 ssize_t ipv6nd_free(struct interface *);
 void ipv6nd_expirera(void *arg);
 bool ipv6nd_hasralifetime(const struct interface *, bool);