https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=289177

            Bug ID: 289177
           Summary: IPv6 temp address(es) with pltime=0 briefly loses
                    deprecated on RA → OS may pick the old address as the
                    source
           Product: Base System
           Version: 14.3-RELEASE
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Many People
          Priority: ---
         Component: kern
          Assignee: [email protected]
          Reporter: [email protected]

IPv6 temp address(es) with pltime=0 briefly loses deprecated on RA → OS may
pick the old address as the source.

[Environment]
OS: FreeBSD 14.3-RELEASE-p2 (amd64, Intel CPU)
Interface: wlan0
SLAAC with temporary/privacy addresses enabled
All IPv6 addresses/prefixes below are obfuscated (e.g.,
2001:db8:1234:5678:aaaa:bbbb:cccc:dddd)

[Summary]
Upon receipt of a Router Advertisement (RA), any existing IPv6 temporary
address(es) whose preferred lifetime has already expired (pltime=0) briefly
loses its deprecated state (~1 s) and then returns to deprecated. During this
flip-flop window, the OS may select that old address as the source for new
outbound connections, causing intermittent ACL denials on remote systems that
whitelist only the current preferred address. This behavior appears
non-compliant with RFC 4862/4941/8981 expectations (a pltime=0 address should
remain deprecated for the rest of its valid lifetime) and can lead to
unexpected, undesirable side effects, including transient exposure of the
user’s old IPv6 addresses, which should not occur.

[Steps to Reproduce]
• Enable temporary addresses and connect to a network that advertises a global
prefix.
• Wait until an older temp address reaches pltime 0 while still having vltime >
0 (deprecated but valid).
• Sample ifconfig <if> inet6 once per second while RAs are being received.
• Observe that on each RA the deprecated address loses the “deprecated” label,
then regains it after ~1 second.

[Expected Behavior]
Once pltime=0, the address should remain deprecated continuously; subsequent
RAs must not create a window where it appears usable for new connections.

[Actual Behavior]
On each RA, the already-expired temporary address(es) becomes non-deprecated
for ~1 second and then flips back to deprecated.

[Impact]
• During the ~1-second flip after each RA, the kernel may select a previously
deprecated temporary address (pltime=0) as the source for new flows.
• Leads to intermittent IP-ACL denials, policy/geofencing mismatches, and flaky
behavior in automation that relies on stable source addresses.
• Privacy risk: transient re-exposure of old temporary IPv6 addresses in
outbound traffic, logs, and third-party telemetry—contrary to the privacy
intent of RFC 4941/8981 rotation.
• Disrupts observability and auditing (source attribution changes mid-session),
complicating incident analysis and per-IP accounting/billing.

[Code details] (FreeBSD 14.3-RELEASE-p2) (by ChatGPT - may have errors)
Where “deprecated” is decided — sys/netinet6/in6.h:
#define IFA6_IS_DEPRECATED(a) \
        ((a)->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME && \
        (u_int32_t)((time_uptime - (a)->ia6_updatetime)) > \
        (a)->ia6_lifetime.ia6t_pltime)

#define IFA6_IS_INVALID(a) \
        ((a)->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME && \
        (u_int32_t)((time_uptime - (a)->ia6_updatetime)) > \
        (a)->ia6_lifetime.ia6t_vltime)
Where RA lifetimes are refreshed — Router Advertisements are processed in
sys/netinet6/nd6_rtr.c (nd6_ra_input(...)). During PIO handling, address
lifetimes are updated and the address “update time” (ia6_updatetime) is
refreshed (via the address/prefix update path in the IPv6 stack).

Why the flip-flop happens (step by step)
1. Before RA: the old temporary address has pltime=0, so it is deprecated.
2. RA arrives → the RA path refreshes lifetimes and sets ia6_updatetime =
time_uptime (now).
3. The predicate becomes:
(time_uptime - ia6_updatetime) > pltime
→ (0) > 0  == false
Thus, for ~1 tick, the address evaluates as non-deprecated.
4. After ~1 second, the left side becomes > 0, the predicate turns true, and
the address is again deprecated.
5. In that short window the kernel may pick the old temp address as a source
for new flows (observed in practice).

[Evidence] (obfuscated sources)
ifconfig wlan0 inet6:
inet6 2001:db8:aaaa:bbbb:5555:6666:7777:8888 prefixlen 64 deprecated autoconf
temporary pltime 0 vltime 400150
# immediately after RA:
inet6 2001:db8:aaaa:bbbb:5555:6666:7777:8888 prefixlen 64 autoconf temporary
pltime 0 vltime 400100   # lost 'deprecated' for ~1s
# next second:
inet6 2001:db8:aaaa:bbbb:5555:6666:7777:8888 prefixlen 64 deprecated autoconf
temporary pltime 0 vltime 400100

$ repeat 500 ( sleep 0.5; ping -o google.com )
...
--- google.com ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 17.833/17.833/17.833/0.000 ms
PING(56=40+8+8 bytes) 2001:db8:aaaa:bbbb:1111:2222:3333:4444 -->
2a00:1450:401b:808::200e
16 bytes from 2a00:1450:401b:808::200e, icmp_seq=0 hlim=120 time=17.495 ms

--- google.com ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 17.495/17.495/17.495/0.000 ms
PING(56=40+8+8 bytes) 2001:db8:aaaa:bbbb:5555:6666:7777:8888 -->
2a00:1450:401b:808::200e  # Used deprecated IPv6 as source
16 bytes from 2a00:1450:401b:808::200e, icmp_seq=0 hlim=118 time=18.777 ms

--- google.com ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 18.777/18.777/18.777/0.000 ms
PING(56=40+8+8 bytes) 2001:db8:aaaa:bbbb:5555:6666:7777:8888 -->
2a00:1450:401b:808::200e  # Used deprecated IPv6 as source
16 bytes from 2a00:1450:401b:808::200e, icmp_seq=0 hlim=118 time=17.698 ms

--- google.com ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 17.698/17.698/17.698/0.000 ms
PING(56=40+8+8 bytes) 2001:db8:aaaa:bbbb:1111:2222:3333:4444 -->
2a00:1450:401b:808::200e
16 bytes from 2a00:1450:401b:808::200e, icmp_seq=0 hlim=120 time=18.116 ms

--- google.com ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 18.116/18.116/18.116/0.000 ms
PING(56=40+8+8 bytes) 2001:db8:aaaa:bbbb:1111:2222:3333:4444 -->
2a00:1450:401b:808::200e
16 bytes from 2a00:1450:401b:808::200e, icmp_seq=0 hlim=120 time=18.183 ms

-- 
You are receiving this mail because:
You are the assignee for the bug.

Reply via email to