From: Roy Marples Date: Sat, 7 May 2016 12:21:35 +0000 (+0000) Subject: Remember the delegating prefix rather than the delegating interface. X-Git-Tag: v6.11.0~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b8a7d9755055dcf60745d96514c2fe2bd18f0e4d;p=thirdparty%2Fdhcpcd.git Remember the delegating prefix rather than the delegating interface. This allows us to clear the NOREJECT flag if we ever delete the delegated address. --- diff --git a/dhcp6.c b/dhcp6.c index 7e37e977..79afd45b 100644 --- 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); @@ -2321,18 +2321,18 @@ 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 *ia, struct interface *ifs) + const struct if_sla *sla, struct if_ia *if_ia) { struct dhcp6_state *state; - struct in6_addr addr; - struct ipv6_addr *a, *ap, *apn; + struct in6_addr addr, daddr; + struct ipv6_addr *ia; char sabuf[INET6_ADDRSTRLEN]; const char *sa; - int pfxlen; + int pfxlen, dadcounter; uint64_t vl; /* RFC6603 Section 4.2 */ - if (strcmp(ifp->name, ifs->name) == 0) { + if (strcmp(ifp->name, prefix->iface->name) == 0) { if (prefix->prefix_exclude_len == 0) { /* Don't spam the log automatically */ if (sla) @@ -2345,7 +2345,7 @@ dhcp6_ifdelegateaddr(struct interface *ifp, struct ipv6_addr *prefix, pfxlen = prefix->prefix_exclude_len; memcpy(&addr, &prefix->prefix_exclude, sizeof(addr)); } else if ((pfxlen = dhcp6_delegateaddr(&addr, ifp, prefix, - sla, ia)) == -1) + sla, if_ia)) == -1) return NULL; if (fls64(sla->suffix) > 128 - pfxlen) { @@ -2355,62 +2355,60 @@ dhcp6_ifdelegateaddr(struct interface *ifp, struct ipv6_addr *prefix, return NULL; } - a = calloc(1, sizeof(*a)); - if (a == NULL) { - logger(ifp->ctx, LOG_ERR, "%s: %m", __func__); - return NULL; - } - a->iface = ifp; - a->flags = IPV6_AF_NEW | IPV6_AF_ONLINK; - a->dadcallback = dhcp6_dadcallback; - a->delegating_iface = ifs; - memcpy(&a->iaid, &prefix->iaid, sizeof(a->iaid)); - a->created = a->acquired = prefix->acquired; - a->prefix_pltime = prefix->prefix_pltime; - a->prefix_vltime = prefix->prefix_vltime; - a->prefix = addr; - a->prefix_len = (uint8_t)pfxlen; - - /* If the prefix length hasn't changed, - * don't install a reject route. */ - if (prefix->prefix_len == pfxlen) - prefix->flags |= IPV6_AF_NOREJECT; - /* Add our suffix */ if (sla->suffix) { - a->addr = addr; + daddr = addr; vl = be64dec(addr.s6_addr + 8); vl |= sla->suffix; - be64enc(a->addr.s6_addr + 8, vl); + be64enc(daddr.s6_addr + 8, vl); } else { - a->dadcounter = ipv6_makeaddr(&a->addr, ifp, - &a->prefix, a->prefix_len); - if (a->dadcounter == -1) { + dadcounter = ipv6_makeaddr(&daddr, ifp, &addr, pfxlen); + if (dadcounter == -1) { logger(ifp->ctx, LOG_ERR, "%s: error adding slaac to prefix_len %d", - ifp->name, a->prefix_len); - free(a); + ifp->name, pfxlen); return NULL; } } + /* Find an existing address */ state = D6_STATE(ifp); - /* Remove any exiting address */ - TAILQ_FOREACH_SAFE(ap, &state->addrs, next, apn) { - if (IN6_ARE_ADDR_EQUAL(&ap->addr, &a->addr)) { - TAILQ_REMOVE(&state->addrs, ap, next); - /* Keep our flags */ - a->flags |= ap->flags; - a->flags &= ~IPV6_AF_NEW; - a->created = ap->created; - ipv6_freeaddr(ap); + TAILQ_FOREACH(ia, &state->addrs, next) { + if (IN6_ARE_ADDR_EQUAL(&ia->addr, &daddr)) + break; + } + if (ia == NULL) { + ia = calloc(1, sizeof(*ia)); + if (ia == NULL) { + logger(ifp->ctx, LOG_ERR, "%s: %m", __func__); + return NULL; } + ia->iface = ifp; + ia->flags = IPV6_AF_NEW | IPV6_AF_ONLINK; + 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; + + TAILQ_INSERT_TAIL(&state->addrs, ia, next); } + ia->delegating_prefix = prefix; + ia->prefix_len = (uint8_t)pfxlen; + ia->prefix_pltime = prefix->prefix_pltime; + ia->prefix_vltime = prefix->prefix_vltime; + + sa = inet_ntop(AF_INET6, &ia->addr, sabuf, sizeof(sabuf)); + snprintf(ia->saddr, sizeof(ia->saddr), "%s/%d", sa, ia->prefix_len); + + /* If the prefix length hasn't changed, + * don't install a reject route. */ + if (prefix->prefix_len == pfxlen) + prefix->flags |= IPV6_AF_NOREJECT; + else + prefix->flags &= ~IPV6_AF_NOREJECT; - sa = inet_ntop(AF_INET6, &a->addr, sabuf, sizeof(sabuf)); - snprintf(a->saddr, sizeof(a->saddr), "%s/%d", sa, a->prefix_len); - TAILQ_INSERT_TAIL(&state->addrs, a, next); - return a; + return ia; } static void @@ -2431,8 +2429,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; @@ -2494,7 +2492,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++) { @@ -2510,7 +2508,7 @@ dhcp6_delegate_prefix(struct interface *ifp) break; } if (dhcp6_ifdelegateaddr(ifd, ap, - sla, ia, ifp)) + sla, ia)) k++; } if (carrier_warned ||abrt) @@ -2576,7 +2574,7 @@ dhcp6_find_delegates(struct interface *ifp) return 1; } if (dhcp6_ifdelegateaddr(ifp, ap, - sla, ia, ifd)) + sla, ia)) k++; } } @@ -3552,7 +3550,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; } } @@ -3565,7 +3563,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 a22f2e11..66f69ea0 100644 --- a/ipv6.c +++ b/ipv6.c @@ -594,6 +594,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)) { @@ -721,7 +728,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) ap->flags |= IPV6_AF_DELEGATED; #ifdef IPV6_POLLADDRFLAG @@ -854,7 +861,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 d20f9435..bf3f20a3 100644 --- a/ipv6.h +++ b/ipv6.h @@ -153,7 +153,7 @@ struct ipv6_addr { char saddr[INET6_ADDRSTRLEN]; uint8_t iaid[4]; uint16_t ia_type; - struct interface *delegating_iface; + struct ipv6_addr *delegating_prefix; uint8_t prefix_exclude_len; struct in6_addr prefix_exclude;