]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Store acquired time for each IPv6 address so we can correctly offset
authorRoy Marples <roy@marples.name>
Tue, 16 Dec 2014 20:20:01 +0000 (20:20 +0000)
committerRoy Marples <roy@marples.name>
Tue, 16 Dec 2014 20:20:01 +0000 (20:20 +0000)
pltime and vltime if we need to re-add them.

dhcp6.c
ipv6.c
ipv6.h
ipv6nd.c

diff --git a/dhcp6.c b/dhcp6.c
index b136489436363df325b268afa4f3de1561c570d4..5b24c6b779704e7c519afebfd99ff1b1a2fbaa44 100644 (file)
--- 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 e66bddd8052addb03d1f7e95bd04d76771acc7ef..6744140b10064330a07931c679e73c85562c16ad 100644 (file)
--- 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 6864bce60d8680d2ce79a12030e92103e7bf55ac..41074c725aa243581c899b0f1281bddb0b29f37a 100644 (file)
--- 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 *);
index 44fdd288af3b740c81698b80959714074fabbdf3..1e45b3b39c83d49c033528afdfc4a33848775b14 100644 (file)
--- 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 =