Skip to content

ipv6: keep an address alive while its prefix is still advertised - #1182

Open
adamgeorge309 wants to merge 2 commits into
masterfrom
topic/gy/ipv6-prefix-lifetime
Open

ipv6: keep an address alive while its prefix is still advertised#1182
adamgeorge309 wants to merge 2 commits into
masterfrom
topic/gy/ipv6-prefix-lifetime

Conversation

@adamgeorge309

Copy link
Copy Markdown
Contributor

A host stored the valid and preferred lifetimes it was given when it first
formed an address from an advertised prefix, and nothing ever updated them. The
router repeating the prefix -- which is how a host is meant to keep the address
it holds -- left them untouched, so the address stayed on the schedule the first
advertisement had set, however long the router kept advertising.

Closes #1180

Two commits: the first adds a getter to a shared component, the second is the
fix that needs it. Read them in that order.

The problem

RFC 4862 Section 5.5.3 step (e) has a host that receives a Prefix Information
option for a prefix it already holds an address from reset that address's
preferred lifetime and, under three sub-cases, its valid lifetime.

processRaPrefixInfoForAddrAutoConf() had no branch for that case at all. It
formed an address when the prefix was new to the interface, took the MIPv6
handover path when the interface held addresses from another prefix, and did
nothing when the same router repeated the same prefix.
Ipv6InterfaceData::updateMatchingAddressExpiryTimes(), which does the storing,
had no caller anywhere in the tree.

The other half of Section 5.5.3 is already implemented: commit 21aca8c made a
Prefix Information option with a zero valid lifetime invalidate the address
autoconfigured from that prefix. Step (e) is the missing half.

The fix

The branch is added with all three sub-cases. The valid lifetime follows the
advertisement when it is longer than two hours or longer than what is left; it
is left alone when two hours or less remain, because the advertisement is not
authenticated; otherwise it is cut to two hours. Those rules are what stops a
forged advertisement carrying short valid lifetimes from expiring every address
of a node, while a legitimate advertisement, which a router repeats, always
takes the first case and applies at once. The preferred lifetime follows the
advertisement in every case, as the step says.

An address with an infinite valid lifetime was not autoconfigured from a Prefix
Information option, so step (e) does not speak about it and the branch leaves it
alone.

Why the first commit is separate

Ipv6InterfaceData stored a per-address valid lifetime expiry and let a caller
set it, through assignAddress() and updateMatchingAddressExpiryTimes(), but
offered no way to read it back, and step (e) has to decide the new valid lifetime
from the lifetime that is left. getAddressExpiryTime(int i) is a change to a
shared component with its own audience, so it is its own commit and comes first
(PR-SPLIT-UPSTREAM). It adds no caller of its own, so it changes no behaviour and
moves no baseline.

Verification

cd tests/fingerprint && ./fingerprinttest -s -F tyf
cd tests/module      && inet_run_module_tests   -m release -f 'IPv6|MIPv6|Ipv6'
cd tests/protocol/ipv6 && inet_run_protocol_tests -m release
bash doc/project/enforcement/check-commits.sh origin/master..HEAD

Unmodified master gives 1774 rows with 3 failures and 62 errors, and so does
this branch. The 62 errors are disabled optional features -- VoIPStream,
TcpLwip, VoipStreamSender -- and have nothing to do with IPv6. The 3 failures
are examples/ipv6/mipv6 Handover and RouteOptimizationTwoCNs and
examples/ipv6/mipv6roaming Roaming, all ~tNlb rows of
mipv6-refactoring.csv. Their recorded values are stale on master already, so
they keep them here; re-recording them would absorb that staleness rather than
fix it.

No fingerprint moves, and none is expected: no shipped example advertises a
lifetime short enough to be reached within its run, so no advertisement in the
suite lands on a prefix the receiving host already holds an address from with a
lifetime worth refreshing. The whole 1774-row suite was still run, on both
commits, to show that.

Module tests: 43 tests, 41 pass. MIPv6_tcp_handover and IPv6_packet_too_big
fail identically on unmodified master. The 43rd is the new
Ipv6_prefix_lifetime_refresh, which fails on master and passes here.

Protocol tests, tests/protocol/ipv6: 29 tests, 21 pass and 8 expected failures
-- the same result as unmodified master.

check-commits.sh passes. check-architecture.sh and check-naming.sh report
only candidates already present on master, in src/inet/applications/sctpapp,
src/inet/applications/rtpapp and images/misc.

Architectural surface

Ipv6InterfaceData gains one const getter, getAddressExpiryTime(int i). No
packet content, configuration surface, feature descriptor or contract changes,
and no sealed path is touched. The new module test is named
Ipv6_prefix_lifetime_refresh.test rather than IPv6_..., so it does not widen
the open NV-16 row; no new AV-* or NV-* row is needed.

Not addressed here

Ipv6InterfaceData::getPreferredAddress() (Ipv6InterfaceData.h:559) and
getGlobalAddress() (Ipv6InterfaceData.cc:777) return an address without
checking whether its lifetimes have run out; both carry a FIXME saying so. And
nothing removes an address when its valid lifetime expires -- it survives until
the next unrelated change to the interface's address list runs
choosePreferredAddress(). Until both are repaired, a stale lifetime has no
effect a running simulation can see, which is why this defect needs a module test
to demonstrate it and moves no fingerprint.

Two further Neighbour Discovery conformance defects are fixed separately, in
#1178 (the initial Router Advertisement clamp) and #1179 (the Duplicate Address
Detection delay).

Ipv6InterfaceData stores a valid lifetime expiry per address and lets a
caller set it, through assignAddress() and updateMatchingAddressExpiryTimes(),
but offers no way to read it back. A caller that has to decide what a new
lifetime should be from the lifetime that is left cannot do so.

Add getAddressExpiryTime(int i), next to the getAddress(int i) and
getAddressType(int i) it matches. Zero means an infinite valid lifetime, the
same convention the stored field already uses.

No caller yet, so no behaviour changes and no baseline moves.
A host stored the valid and preferred lifetimes it was given when it first
formed an address from an advertised prefix, and nothing ever updated them.
The router repeating the prefix -- which is how a host is meant to keep the
address it holds -- left them untouched, so the address stayed on the
schedule the first advertisement had set, however long the router kept
advertising.

RFC 4862 Section 5.5.3 gives the rule as step (e):

    If the advertised prefix is equal to the prefix of an address
    configured by stateless autoconfiguration in the list, the preferred
    lifetime of the address is reset to the Preferred Lifetime in the
    received advertisement.  The specific action to perform for the valid
    lifetime of the address depends on the Valid Lifetime in the received
    advertisement and the remaining time to the valid lifetime expiration
    of the previously autoconfigured address.

processRaPrefixInfoForAddrAutoConf() had no branch for it. It formed an
address when the prefix was new to the interface, took the MIPv6 handover
path when the interface held addresses from another prefix, and did nothing
at all in the case step (e) describes: the same prefix advertised again to a
host already configured from it.

Add that branch, with the three sub-cases the step lists. The valid lifetime
follows the advertisement when it is longer than two hours or longer than
what is left; it is left alone when two hours or less remain, because the
advertisement is not authenticated; otherwise it is cut to two hours. Those
rules are what stops a forged advertisement carrying short valid lifetimes
from expiring every address of a node, while a legitimate advertisement,
which a router repeats, always takes the first case and applies at once. The
preferred lifetime follows the advertisement in every case, as the step says.

Ipv6InterfaceData::updateMatchingAddressExpiryTimes() already did the
storing; it had no caller until now.

An address with an infinite valid lifetime was not autoconfigured from a
Prefix Information option, so step (e) does not speak about it and the
branch leaves it alone.

The new Ipv6_prefix_lifetime_refresh module test advertises a prefix with a
20 s valid lifetime and a 10 s preferred lifetime every 4 s to 6 s over a
60 s run, and checks that the host forms one address and then keeps
refreshing it. It fails on master, where the refresh never happens.

No fingerprint moves: no shipped example advertises a lifetime short enough
to be reached within its run, so no advertisement in the suite lands on a
prefix the receiving host already holds an address from with a lifetime worth
refreshing.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ipv6: a repeated Prefix Information option never refreshes the lifetimes of an address formed from that prefix

1 participant