From: Roy Marples Date: Tue, 16 Dec 2014 20:20:01 +0000 (+0000) Subject: Store acquired time for each IPv6 address so we can correctly offset X-Git-Tag: v6.6.6~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0b3255ac875375112d273cca8223c22dfe3af12d;p=thirdparty%2Fdhcpcd.git Store acquired time for each IPv6 address so we can correctly offset pltime and vltime if we need to re-add them. --- diff --git a/dhcp6.c b/dhcp6.c index b1364894..5b24c6b7 100644 --- a/dhcp6.c +++ b/dhcp6.c @@ -1695,7 +1695,7 @@ dhcp6_findaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr, static int dhcp6_findna(struct interface *ifp, uint16_t ot, const uint8_t *iaid, - const uint8_t *d, size_t l) + const uint8_t *d, size_t l, const struct timeval *acquired) { struct dhcp6_state *state; const struct dhcp6_option *o; @@ -1757,6 +1757,7 @@ dhcp6_findna(struct interface *ifp, uint16_t ot, const uint8_t *iaid, a->flags |= IPV6_AF_ONLINK | IPV6_AF_NEW; a->flags &= ~IPV6_AF_STALE; } + a->acquired = *acquired; a->prefix_pltime = ntohl(iap->pltime); u32 = ntohl(iap->vltime); if (a->prefix_vltime != u32) { @@ -1774,7 +1775,7 @@ dhcp6_findna(struct interface *ifp, uint16_t ot, const uint8_t *iaid, static int dhcp6_findpd(struct interface *ifp, const uint8_t *iaid, - const uint8_t *d, size_t l) + const uint8_t *d, size_t l, const struct timeval *acquired) { struct dhcp6_state *state; const struct dhcp6_option *o, *ex; @@ -1835,6 +1836,7 @@ dhcp6_findpd(struct interface *ifp, const uint8_t *iaid, a->flags |= IPV6_AF_NEW; } + a->acquired = *acquired; a->prefix_pltime = ntohl(pdp->pltime); a->prefix_vltime = ntohl(pdp->vltime); @@ -1898,7 +1900,7 @@ dhcp6_findpd(struct interface *ifp, const uint8_t *iaid, static int dhcp6_findia(struct interface *ifp, const struct dhcp6_message *m, size_t l, - const char *sfrom) + const char *sfrom, const struct timeval *acquired) { struct dhcp6_state *state; const struct if_options *ifo; @@ -1992,7 +1994,7 @@ dhcp6_findia(struct interface *ifp, const struct dhcp6_message *m, size_t l, } if (code == D6_OPTION_IA_PD) { if (!(ifo->options & DHCPCD_NOPFXDLG) && - dhcp6_findpd(ifp, iaid, p, ol) == 0) + dhcp6_findpd(ifp, iaid, p, ol, acquired) == 0) { syslog(LOG_WARNING, "%s: %s: DHCPv6 REPLY missing Prefix", @@ -2000,7 +2002,8 @@ dhcp6_findia(struct interface *ifp, const struct dhcp6_message *m, size_t l, continue; } } else if (!(ifo->options & DHCPCD_PFXDLGONLY)) { - if (dhcp6_findna(ifp, code, iaid, p, ol) == 0) { + if (dhcp6_findna(ifp, code, iaid, p, ol, acquired) == 0) + { syslog(LOG_WARNING, "%s: %s: DHCPv6 REPLY missing IA Address", ifp->name, sfrom); @@ -2046,10 +2049,11 @@ dhcp6_findia(struct interface *ifp, const struct dhcp6_message *m, size_t l, static int dhcp6_validatelease(struct interface *ifp, const struct dhcp6_message *m, size_t len, - const char *sfrom) + const char *sfrom, const struct timeval *acquired) { struct dhcp6_state *state; int nia; + struct timeval aq; if (len <= sizeof(*m)) { syslog(LOG_ERR, "%s: DHCPv6 lease truncated", ifp->name); @@ -2062,7 +2066,11 @@ dhcp6_validatelease(struct interface *ifp, state->renew = state->rebind = state->expire = 0; state->lowpl = ND6_INFINITE_LIFETIME; - nia = dhcp6_findia(ifp, m, len, sfrom); + if (!acquired) { + get_monotonic(&aq); + acquired = &aq; + } + nia = dhcp6_findia(ifp, m, len, sfrom, acquired); if (nia == 0) { syslog(LOG_ERR, "%s: no useable IA found in lease", ifp->name); @@ -2101,6 +2109,7 @@ dhcp6_readlease(struct interface *ifp) ssize_t bytes; struct timeval now; const struct dhcp6_option *o; + struct timeval acquired; state = D6_STATE(ifp); if (stat(state->leasefile, &st) == -1) { @@ -2134,15 +2143,19 @@ dhcp6_readlease(struct interface *ifp) goto ex; } + gettimeofday(&now, NULL); + get_monotonic(&acquired); + acquired.tv_sec -= now.tv_sec - st.st_mtime; + /* Check to see if the lease is still valid */ - fd = dhcp6_validatelease(ifp, state->new, state->new_len, NULL); + fd = dhcp6_validatelease(ifp, state->new, state->new_len, NULL, + &acquired); if (fd == -1) goto ex; if (!(ifp->ctx->options & DHCPCD_DUMPLEASE) && state->expire != ND6_INFINITE_LIFETIME) { - gettimeofday(&now, NULL); if ((time_t)state->expire < now.tv_sec - st.st_mtime) { syslog(LOG_DEBUG,"%s: discarding expired lease", ifp->name); @@ -2271,6 +2284,7 @@ dhcp6_ifdelegateaddr(struct interface *ifp, struct ipv6_addr *prefix, a->dadcallback = dhcp6_dadcallback; a->delegating_iface = ifs; memcpy(&a->iaid, &prefix->iaid, sizeof(a->iaid)); + a->acquired = prefix->acquired; a->prefix_pltime = prefix->prefix_pltime; a->prefix_vltime = prefix->prefix_vltime; a->prefix = addr; @@ -2723,7 +2737,8 @@ dhcp6_handledata(void *arg) if (error == 1) goto recv; if (error == -1 || - dhcp6_validatelease(ifp, r, len, ctx->sfrom) == -1) + dhcp6_validatelease(ifp, r, len, + ctx->sfrom, NULL) == -1) { dhcp6_startdiscover(ifp); return; @@ -2739,7 +2754,9 @@ dhcp6_handledata(void *arg) case DH6S_REQUEST: /* FALLTHROUGH */ case DH6S_RENEW: /* FALLTHROUGH */ case DH6S_REBIND: - if (dhcp6_validatelease(ifp, r, len, ctx->sfrom) == -1){ + if (dhcp6_validatelease(ifp, r, len, + ctx->sfrom, NULL) == -1) + { /* PD doesn't use CONFIRM, so REBIND could * throw up an invalid prefix if we * changed link */ @@ -2784,7 +2801,7 @@ dhcp6_handledata(void *arg) syslog(LOG_ERR, "%s: invalid INF_MAX_RT %d", ifp->name, u32); } - if (dhcp6_validatelease(ifp, r, len, ctx->sfrom) == -1) + if (dhcp6_validatelease(ifp, r, len, ctx->sfrom, NULL) == -1) return; break; case DHCP6_RECONFIGURE: diff --git a/ipv6.c b/ipv6.c index e66bddd8..6744140b 100644 --- a/ipv6.c +++ b/ipv6.c @@ -602,11 +602,13 @@ ipv6_deleteaddr(struct ipv6_addr *addr) } int -ipv6_addaddr(struct ipv6_addr *ap) +ipv6_addaddr(struct ipv6_addr *ap, const struct timeval *now) { struct interface *ifp; struct ipv6_state *state; struct ipv6_addr *nap; + struct timeval n; + uint32_t pltime, vltime; /* Ensure no other interface has this address */ TAILQ_FOREACH(ifp, ap->iface->ctx->ifaces, next) { @@ -623,6 +625,24 @@ ipv6_addaddr(struct ipv6_addr *ap) } } + /* Adjust plftime and vltime based on acquired time */ + pltime = ap->prefix_pltime; + vltime = ap->prefix_vltime; + if (timerisset(&ap->acquired) && + (ap->prefix_pltime != ND6_INFINITE_LIFETIME || + ap->prefix_vltime != ND6_INFINITE_LIFETIME)) + { + if (now == NULL) { + get_monotonic(&n); + now = &n; + } + timersub(now, &ap->acquired, &n); + if (ap->prefix_pltime != ND6_INFINITE_LIFETIME) + ap->prefix_pltime -= n.tv_sec; + if (ap->prefix_vltime != ND6_INFINITE_LIFETIME) + ap->prefix_vltime -= n.tv_sec; + } + syslog(ap->flags & IPV6_AF_NEW ? LOG_INFO : LOG_DEBUG, "%s: adding address %s", ap->iface->name, ap->saddr); if (!(ap->flags & IPV6_AF_DADCOMPLETED) && @@ -630,8 +650,15 @@ ipv6_addaddr(struct ipv6_addr *ap) ap->flags |= IPV6_AF_DADCOMPLETED; if (if_addaddress6(ap) == -1) { syslog(LOG_ERR, "if_addaddress6: %m"); + /* Restore real pltime and vltime */ + ap->prefix_pltime = pltime; + ap->prefix_vltime = vltime; return -1; } + + /* Restore real pltime and vltime */ + ap->prefix_pltime = pltime; + ap->prefix_vltime = vltime; ap->flags &= ~IPV6_AF_NEW; ap->flags |= IPV6_AF_ADDED; if (ap->delegating_iface) @@ -695,8 +722,10 @@ ipv6_addaddrs(struct ipv6_addrhead *addrs) { struct ipv6_addr *ap, *apn, *apf; ssize_t i; + struct timeval now; i = 0; + timerclear(&now); TAILQ_FOREACH_SAFE(ap, addrs, next, apn) { if (ap->prefix_vltime == 0) { if (ap->flags & IPV6_AF_ADDED) { @@ -741,7 +770,9 @@ ipv6_addaddrs(struct ipv6_addrhead *addrs) apf->flags &= ~IPV6_AF_ADDED; if (ap->flags & IPV6_AF_NEW) i++; - ipv6_addaddr(ap); + if (!timerisset(&now)) + get_monotonic(&now); + ipv6_addaddr(ap, &now); } } @@ -753,7 +784,9 @@ ipv6_freedrop_addrs(struct ipv6_addrhead *addrs, int drop, const struct interface *ifd) { struct ipv6_addr *ap, *apn, *apf; + struct timeval now; + timerclear(&now); TAILQ_FOREACH_SAFE(ap, addrs, next, apn) { if (ifd && ap->delegating_iface != ifd) continue; @@ -772,7 +805,11 @@ ipv6_freedrop_addrs(struct ipv6_addrhead *addrs, int drop, ipv6_deleteaddr(ap); if (!(ap->iface->options->options & DHCPCD_EXITING) && apf) - ipv6_addaddr(apf); + { + if (!timerisset(&now)) + get_monotonic(&now); + ipv6_addaddr(apf, &now); + } } free(ap); } @@ -1078,7 +1115,7 @@ nextslaacprivate: inet_ntop(AF_INET6, &ap->addr, ap->saddr, sizeof(ap->saddr)); TAILQ_INSERT_TAIL(&state->addrs, ap, next); - ipv6_addaddr(ap); + ipv6_addaddr(ap, NULL); return 1; } diff --git a/ipv6.h b/ipv6.h index 6864bce6..41074c72 100644 --- a/ipv6.h +++ b/ipv6.h @@ -83,6 +83,7 @@ struct ipv6_addr { uint8_t prefix_len; uint32_t prefix_vltime; uint32_t prefix_pltime; + struct timeval acquired; struct in6_addr addr; int addr_flags; short flags; @@ -180,7 +181,7 @@ uint8_t ipv6_prefixlen(const struct in6_addr *); int ipv6_userprefix( const struct in6_addr *, short prefix_len, uint64_t user_number, struct in6_addr *result, short result_len); void ipv6_checkaddrflags(void *); -int ipv6_addaddr(struct ipv6_addr *); +int ipv6_addaddr(struct ipv6_addr *, const struct timeval *); ssize_t ipv6_addaddrs(struct ipv6_addrhead *addrs); void ipv6_freedrop_addrs(struct ipv6_addrhead *, int, const struct interface *); diff --git a/ipv6nd.c b/ipv6nd.c index 44fdd288..1e45b3b3 100644 --- a/ipv6nd.c +++ b/ipv6nd.c @@ -549,7 +549,7 @@ ipv6nd_addaddr(void *arg) { struct ipv6_addr *ap = arg; - ipv6_addaddr(ap); + ipv6_addaddr(ap, NULL); } int @@ -896,6 +896,7 @@ ipv6nd_handlera(struct ipv6_ctx *ctx, struct interface *ifp, if (pi->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) ap->flags |= IPV6_AF_ONLINK; + ap->acquired = rap->received; ap->prefix_vltime = ntohl(pi->nd_opt_pi_valid_time); ap->prefix_pltime =