When a Router Advertisement carries a Prefix Information Option with
the autonomous flag set, addrconf_prefix_rcv_add_addr() looks up the
address that SLAAC would form from the prefix. If an address with that
value already exists on the interface, its valid and preferred
lifetimes are refreshed from the PIO, regardless of how the address
was created.
RFC 4862 Section 5.5.3 e) only requires this for "an address
configured by stateless autoconfiguration". A manually configured
address that happens to match the SLAAC-derived address, e.g. a static
EUI-64 address in an advertised prefix, has its infinite lifetimes
replaced with the finite ones from the RA. The address then expires
and is removed once the router stops advertising the prefix, even
though the administrator configured it as permanent.
This is easy to hit on a router that accepts RAs on an interface that
it also advertises a prefix on with an EUI-64 address configured from
that prefix: its own RAs turn the configured address into one with
finite lifetimes. If the RA daemon advertises the remaining lifetime
of the address (e.g. radvd with DecrementLifetimes), the advertised
lifetimes then count down on every RA.
Addresses created by SLAAC are marked with IFA_F_MANAGETEMPADDR, so
only refresh the lifetimes of addresses carrying that flag. A user
can still opt in to RA-driven lifetime management of a manually added
address by adding it with the mngtmpaddr flag.
Signed-off-by: Hermin Anggawijaya <redacted>
---
net/ipv6/addrconf.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index c8c0dd04982d..43d80f09229b 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2762,6 +2762,15 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
unsigned long now;
u32 stored_lft;
+ /* RFC 4862 Section 5.5.3e only applies to addresses
+ * configured by stateless autoconfiguration. Leave the
+ * lifetimes of manually configured addresses alone.
+ */
+ if (!(ifp->flags & IFA_F_MANAGETEMPADDR)) {
+ in6_ifa_put(ifp);
+ return 0;
+ }
+
/* update lifetime (RFC2462 5.5.3 e) */
spin_lock_bh(&ifp->lock);
now = jiffies;--
2.56.0