]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
When removing delegated addresses, ensure the reject route is restored.
authorRoy Marples <roy@marples.name>
Sat, 7 May 2016 20:40:40 +0000 (20:40 +0000)
committerRoy Marples <roy@marples.name>
Sat, 7 May 2016 20:40:40 +0000 (20:40 +0000)
dhcp6.c
ipv6.c
ipv6.h

diff --git a/dhcp6.c b/dhcp6.c
index 3270a8df7f6549e94cce6cddddd40ac17b8726b5..6c15e86f07a09fe24c50acc4bb27ae67f6165f73 100644 (file)
--- a/dhcp6.c
+++ b/dhcp6.c
@@ -1273,7 +1273,7 @@ dhcp6_dadcallback(void *arg)
                {
                        struct ipv6_addr *ap2;
 
-                       valid = (ap->delegating_iface == NULL);
+                       valid = (ap->delegating_prefix == NULL);
                        TAILQ_FOREACH(ap2, &state->addrs, next) {
                                if (ap2->flags & IPV6_AF_ADDED &&
                                    !(ap2->flags & IPV6_AF_DADCOMPLETED))
@@ -1286,7 +1286,7 @@ dhcp6_dadcallback(void *arg)
                                logger(ap->iface->ctx, LOG_DEBUG,
                                    "%s: DHCPv6 DAD completed", ifp->name);
                                script_runreason(ifp,
-                                   ap->delegating_iface ?
+                                   ap->delegating_prefix ?
                                    "DELEGATED6" : state->reason);
                                if (valid)
                                        dhcpcd_daemonise(ifp->ctx);
@@ -1878,10 +1878,13 @@ dhcp6_findpd(struct interface *ifp, const uint8_t *iaid,
                            iabuf, sizeof(iabuf));
                        snprintf(a->saddr, sizeof(a->saddr),
                            "%s/%d", ia, a->prefix_len);
+                       TAILQ_INIT(&a->pd_pfxs);
                        TAILQ_INSERT_TAIL(&state->addrs, a, next);
                } else {
-                       if (!(a->flags & IPV6_AF_DELEGATEDPFX))
+                       if (!(a->flags & IPV6_AF_DELEGATEDPFX)) {
                                a->flags |= IPV6_AF_NEW | IPV6_AF_DELEGATEDPFX;
+                               TAILQ_INIT(&a->pd_pfxs);
+                       }
                        a->flags &= ~(IPV6_AF_STALE | IPV6_AF_REQUEST);
                        if (a->prefix_vltime != ntohl(pdp->vltime))
                                a->flags |= IPV6_AF_NEW;
@@ -2321,7 +2324,7 @@ dhcp6_startinit(struct interface *ifp)
 
 static struct ipv6_addr *
 dhcp6_ifdelegateaddr(struct interface *ifp, struct ipv6_addr *prefix,
-    const struct if_sla *sla, struct if_ia *if_ia, struct interface *ifs)
+    const struct if_sla *sla, struct if_ia *if_ia)
 {
        struct dhcp6_state *state;
        struct in6_addr addr, daddr;
@@ -2388,12 +2391,13 @@ dhcp6_ifdelegateaddr(struct interface *ifp, struct ipv6_addr *prefix,
                ia->dadcallback = dhcp6_dadcallback;
                memcpy(&ia->iaid, &prefix->iaid, sizeof(ia->iaid));
                ia->created = ia->acquired = prefix->acquired;
-               ia->prefix = addr;
-               ia->prefix_len = (uint8_t)pfxlen;
+               ia->addr = daddr;
 
                TAILQ_INSERT_TAIL(&state->addrs, ia, next);
+               TAILQ_INSERT_TAIL(&prefix->pd_pfxs, ia, pd_next);
        }
-       ia->delegating_iface = ifs;
+       ia->delegating_prefix = prefix;
+       ia->prefix = addr;
        ia->prefix_len = (uint8_t)pfxlen;
        ia->prefix_pltime = prefix->prefix_pltime;
        ia->prefix_vltime = prefix->prefix_vltime;
@@ -2429,8 +2433,8 @@ dhcp6_script_try_run(struct interface *ifp, int delegated)
                            ipv6_iffindaddr(ap->iface, &ap->addr, IN6_IFF_TENTATIVE))
                                ap->flags |= IPV6_AF_DADCOMPLETED;
                        if ((ap->flags & IPV6_AF_DADCOMPLETED) == 0 &&
-                           ((delegated && ap->delegating_iface) ||
-                           (!delegated && !ap->delegating_iface)))
+                           ((delegated && ap->delegating_prefix) ||
+                           (!delegated && !ap->delegating_prefix)))
                        {
                                completed = 0;
                                break;
@@ -2492,7 +2496,7 @@ dhcp6_delegate_prefix(struct interface *ifp)
                                                break;
                                        }
                                        if (dhcp6_ifdelegateaddr(ifd, ap,
-                                           NULL, ia, ifp))
+                                           NULL, ia))
                                                k++;
                                }
                                for (j = 0; j < ia->sla_len; j++) {
@@ -2508,7 +2512,7 @@ dhcp6_delegate_prefix(struct interface *ifp)
                                                break;
                                        }
                                        if (dhcp6_ifdelegateaddr(ifd, ap,
-                                           sla, ia, ifp))
+                                           sla, ia))
                                                k++;
                                }
                                if (carrier_warned ||abrt)
@@ -2574,7 +2578,7 @@ dhcp6_find_delegates(struct interface *ifp)
                                                return 1;
                                        }
                                        if (dhcp6_ifdelegateaddr(ifp, ap,
-                                           sla, ia, ifd))
+                                           sla, ia))
                                            k++;
                                }
                        }
@@ -3356,7 +3360,9 @@ dhcp6_freedrop(struct interface *ifp, int drop, const char *reason)
                        return;
                }
 
-               if (drop && options & DHCPCD_RELEASE) {
+               if (drop && options & DHCPCD_RELEASE &&
+                   state->state != DH6S_DELEGATED)
+               {
                        if (ifp->carrier == LINK_UP &&
                            state->state != DH6S_RELEASED)
                        {
@@ -3550,7 +3556,7 @@ delegated:
        state = D6_CSTATE(ifp);
        i = 0;
        TAILQ_FOREACH(ap, &state->addrs, next) {
-               if (ap->delegating_iface) {
+               if (ap->delegating_prefix) {
                        i += strlen(ap->saddr) + 1;
                }
        }
@@ -3563,7 +3569,7 @@ delegated:
                }
                v += snprintf(val, i, "%s_delegated_dhcp6_prefix=", prefix);
                TAILQ_FOREACH(ap, &state->addrs, next) {
-                       if (ap->delegating_iface) {
+                       if (ap->delegating_prefix) {
                                /* Can't use stpcpy(3) due to "security" */
                                const char *sap = ap->saddr;
 
diff --git a/ipv6.c b/ipv6.c
index eebc790f5f5e5e3842304cb6018e173a632a15dd..1c4ffefa269c7be6828936d1737657e5b231ff29 100644 (file)
--- a/ipv6.c
+++ b/ipv6.c
@@ -593,6 +593,13 @@ ipv6_deleteaddr(struct ipv6_addr *ia)
            errno != EADDRNOTAVAIL && errno != ENXIO && errno != ENODEV)
                logger(ia->iface->ctx, LOG_ERR, "if_deladdress6: :%m");
 
+       /* NOREJECT is set if we delegated exactly the prefix to another
+        * address.
+        * This can only be one address, so just clear the flag.
+        * This should ensure the reject route will be restored. */
+       if (ia->delegating_prefix != NULL)
+               ia->delegating_prefix->flags &= ~IPV6_AF_NOREJECT;
+
        state = IPV6_STATE(ia->iface);
        TAILQ_FOREACH(ap, &state->addrs, next) {
                if (IN6_ARE_ADDR_EQUAL(&ap->addr, &ia->addr)) {
@@ -720,7 +727,7 @@ ipv6_addaddr(struct ipv6_addr *ap, const struct timespec *now)
 
        ap->flags &= ~IPV6_AF_NEW;
        ap->flags |= IPV6_AF_ADDED;
-       if (ap->delegating_iface)
+       if (ap->delegating_prefix != NULL)
                ap->flags |= IPV6_AF_DELEGATED;
 
 #ifdef IPV6_POLLADDRFLAG
@@ -839,6 +846,16 @@ ipv6_addaddrs(struct ipv6_addrhead *addrs)
 void
 ipv6_freeaddr(struct ipv6_addr *ap)
 {
+       struct ipv6_addr *ia;
+
+       /* Forget the reference */
+       if (ap->flags & IPV6_AF_DELEGATEDPFX) {
+               TAILQ_FOREACH(ia, &ap->pd_pfxs, pd_next) {
+                       ia->delegating_prefix = NULL;
+               }
+       } else if (ap->delegating_prefix != NULL) {
+               TAILQ_REMOVE(&ap->delegating_prefix->pd_pfxs, ap, pd_next);
+       }
 
        eloop_q_timeout_delete(ap->iface->ctx->eloop, 0, NULL, ap);
        free(ap);
@@ -853,7 +870,9 @@ ipv6_freedrop_addrs(struct ipv6_addrhead *addrs, int drop,
 
        timespecclear(&now);
        TAILQ_FOREACH_SAFE(ap, addrs, next, apn) {
-               if (ifd && ap->delegating_iface != ifd)
+               if (ifd != NULL &&
+                   (ap->delegating_prefix == NULL ||
+                   ap->delegating_prefix->iface != ifd))
                        continue;
                if (drop != 2)
                        TAILQ_REMOVE(addrs, ap, next);
diff --git a/ipv6.h b/ipv6.h
index d20f9435402348ea69ecbbe8097a406700e03248..5ae8426bc38fdccaf8ad2091c2837037f0414722 100644 (file)
--- a/ipv6.h
+++ b/ipv6.h
 #define IN6_IFF_NOTUSEABLE \
        (IN6_IFF_TENTATIVE | IN6_IFF_DUPLICATED | IN6_IFF_DETACHED)
 
+TAILQ_HEAD(ipv6_addrhead, ipv6_addr);
 struct ipv6_addr {
        TAILQ_ENTRY(ipv6_addr) next;
        struct interface *iface;
@@ -153,7 +154,11 @@ struct ipv6_addr {
        char saddr[INET6_ADDRSTRLEN];
        uint8_t iaid[4];
        uint16_t ia_type;
-       struct interface *delegating_iface;
+
+       struct ipv6_addr *delegating_prefix;
+       struct ipv6_addrhead pd_pfxs;
+       TAILQ_ENTRY(ipv6_addr) pd_next;
+
        uint8_t prefix_exclude_len;
        struct in6_addr prefix_exclude;
 
@@ -163,7 +168,6 @@ struct ipv6_addr {
        size_t nslen;
        int nsprobes;
 };
-TAILQ_HEAD(ipv6_addrhead, ipv6_addr);
 
 #define        IPV6_AF_ONLINK          0x0001
 #define        IPV6_AF_NEW             0x0002