Repository navigation
ipv6: send ICMPv6 Redirects only to neighbours, with a link-local target and at a limited rate #1236
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
adamgeorge309
wants to merge
3
commits into
master
Choose a base branch
from
topic/gy/ipv6-redirect
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
ipv6: send ICMPv6 Redirects only to neighbours, with a link-local target and at a limited rate #1236
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| %description: | ||
| Tests that a router limits the rate of the ICMPv6 Redirects it sends | ||
| (RFC 4861 Section 8.2: "A router MUST limit the rate at which Redirect | ||
| messages are sent"), with the token bucket of RFC 4443 Section 2.4 (f). | ||
|
|
||
| Topology: hostA, r1 and r2 on one switch; hostB behind r2. hostA's route to | ||
| hostB goes via r1, and r1's route goes via the link-local address of r2, back | ||
| out the interface the echo requests arrived on, so every echo request makes | ||
| r1 send a Redirect. hostA discards each one, because its route names r1 by | ||
| its global address, not by the link-local source of the Redirect, and keeps | ||
| sending through r1. | ||
|
|
||
| hostA sends 40 echo requests, one per 50 ms, from t=2s to t=3.95s. With a | ||
| burst of 5 and a rate of 2 per second, the bucket allows 5 + 2 * 1.95 = 8.9 | ||
| Redirects over that time, so r1 sends 8 in all. The postrun command counts | ||
| every Redirect r1 sends. | ||
|
|
||
| %#-------------------------------------------------------------------------------------------------------------- | ||
| %file: test.ned | ||
| import inet.networklayer.configurator.ipv6.Ipv6NetworkConfigurator; | ||
| import inet.node.ethernet.Eth100M; | ||
| import inet.node.ethernet.EthernetSwitch; | ||
| import inet.node.inet.Router; | ||
| import inet.node.inet.StandardHost; | ||
|
|
||
| network RedirectRateLimit | ||
| { | ||
| submodules: | ||
| configurator: Ipv6NetworkConfigurator; | ||
| hostA: StandardHost; | ||
| sw: EthernetSwitch; | ||
| r1: Router; | ||
| r2: Router; | ||
| hostB: StandardHost; | ||
| connections: | ||
| hostA.ethg++ <--> Eth100M <--> sw.ethg++; | ||
| r1.ethg++ <--> Eth100M <--> sw.ethg++; | ||
| r2.ethg++ <--> Eth100M <--> sw.ethg++; | ||
| r2.ethg++ <--> Eth100M <--> hostB.ethg++; | ||
| } | ||
| %#-------------------------------------------------------------------------------------------------------------- | ||
| %file: redirect.xml | ||
| <config> | ||
| <interface hosts="hostA" names="eth0" address="2001:db8:2::10"/> | ||
| <interface hosts="r1" names="eth0" address="2001:db8:2::2"/> | ||
| <interface hosts="r2" names="eth0" address="2001:db8:2::3"/> | ||
| <interface hosts="r2" names="eth1" address="2001:db8:4::1"/> | ||
| <interface hosts="hostB" names="eth0" address="2001:db8:4::2"/> | ||
|
|
||
| <route hosts="hostA" destination="2001:db8:4::" prefixLength="64" gateway="2001:db8:2::2" interface="eth0"/> | ||
| <route hosts="r1" destination="2001:db8:4::" prefixLength="64" gateway="fe80::8aa:ff:fe00:6" interface="eth0"/> | ||
| <route hosts="hostB" destination="2001:db8:2::" prefixLength="64" gateway="2001:db8:4::1" interface="eth0"/> | ||
| </config> | ||
| %#-------------------------------------------------------------------------------------------------------------- | ||
| %inifile: omnetpp.ini | ||
| [General] | ||
| record-vector-results = false | ||
| ned-path = ../../../../src;. | ||
| network = RedirectRateLimit | ||
| sim-time-limit = 4.1s | ||
| cmdenv-express-mode = false | ||
| cmdenv-log-prefix = "%C: " | ||
|
|
||
| **.hasIpv4 = false | ||
| **.hasIpv6 = true | ||
| **.ipv6.configurator.networkConfiguratorModule = "configurator" | ||
| **.ipv6.neighbourDiscovery.dupAddrDetectTransmits = 0 | ||
| *.configurator.addStaticRoutes = true | ||
| *.configurator.addRemoteRoutes = false | ||
| *.configurator.addDefaultRoutes = false | ||
| *.configurator.config = xmldoc("redirect.xml") | ||
| *.r1.ipv6.routingTable.routes = xml("<routingTable><local node='r1'><interface name='eth0' AdvSendAdvertisements='off'/></local></routingTable>") | ||
| *.r2.ipv6.routingTable.routes = xml("<routingTable><local node='r2'><interface name='eth0' AdvSendAdvertisements='off'/><interface name='eth1' AdvSendAdvertisements='off'/></local></routingTable>") | ||
|
|
||
| *.hostA.numApps = 1 | ||
| *.hostA.app[0].typename = "PingApp" | ||
| *.hostA.app[0].destAddr = "2001:db8:4::2" | ||
| *.hostA.app[0].startTime = 2s | ||
| *.hostA.app[0].stopTime = 3.99s | ||
| *.hostA.app[0].sendInterval = 50ms | ||
| *.r1.ipv6.neighbourDiscovery.redirectRate = 2Hz | ||
| *.r1.ipv6.neighbourDiscovery.redirectBurst = 5 | ||
| %#-------------------------------------------------------------------------------------------------------------- | ||
| %subst: /omnetpp::// | ||
| %#-------------------------------------------------------------------------------------------------------------- | ||
| %postrun-command: grep -c "RedirectRateLimit.r1.ipv6.neighbourDiscovery: Sending ICMPv6 Redirect" test.out > test_redirects.out || true | ||
| %contains-regex: test_redirects.out | ||
| ^8$ | ||
| %#-------------------------------------------------------------------------------------------------------------- | ||
| %contains: stdout | ||
| RedirectRateLimit.r1.ipv6.neighbourDiscovery: Not sending ICMPv6 Redirect to 2001:db8:2::10 for 2001:db8:4::2: rate limit reached | ||
| %#-------------------------------------------------------------------------------------------------------------- | ||
| %postrun-command: grep "undisposed object:" test.out > test_undisposed.out || true | ||
| %not-contains: test_undisposed.out | ||
| undisposed object: ( | ||
| %#-------------------------------------------------------------------------------------------------------------- |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| %description: | ||
| Tests that a router sends no ICMPv6 Redirect to a source that is not a | ||
| neighbour (RFC 4861 Section 8.2: "the Source Address field of the packet | ||
| identifies a neighbor"). | ||
|
|
||
| Topology: hostA -- r0 -- [switch: r0, r1, r2] -- r2 -- hostB. | ||
| hostA pings hostB. r0 forwards the echo requests to r1, whose route sends | ||
| them back out the same interface to r2. The source of each forwarded echo | ||
| request, hostA, is two hops away from r1, so r1 must not send it a Redirect. | ||
| r2 still forwards the echo requests, and hostB answers them. | ||
|
|
||
| %#-------------------------------------------------------------------------------------------------------------- | ||
| %file: test.ned | ||
| import inet.networklayer.configurator.ipv6.Ipv6NetworkConfigurator; | ||
| import inet.node.ethernet.Eth100M; | ||
| import inet.node.ethernet.EthernetSwitch; | ||
| import inet.node.inet.Router; | ||
| import inet.node.inet.StandardHost; | ||
|
|
||
| network RedirectSourceNotNeighbour | ||
| { | ||
| submodules: | ||
| configurator: Ipv6NetworkConfigurator; | ||
| hostA: StandardHost; | ||
| r0: Router; | ||
| sw: EthernetSwitch; | ||
| r1: Router; | ||
| r2: Router; | ||
| hostB: StandardHost; | ||
| connections: | ||
| hostA.ethg++ <--> Eth100M <--> r0.ethg++; | ||
| r0.ethg++ <--> Eth100M <--> sw.ethg++; | ||
| r1.ethg++ <--> Eth100M <--> sw.ethg++; | ||
| r2.ethg++ <--> Eth100M <--> sw.ethg++; | ||
| r2.ethg++ <--> Eth100M <--> hostB.ethg++; | ||
| } | ||
| %#-------------------------------------------------------------------------------------------------------------- | ||
| %file: redirect.xml | ||
| <config> | ||
| <interface hosts="hostA" names="eth0" address="2001:db8:1::1"/> | ||
| <interface hosts="r0" names="eth0" address="2001:db8:1::2"/> | ||
| <interface hosts="r0" names="eth1" address="2001:db8:2::1"/> | ||
| <interface hosts="r1" names="eth0" address="2001:db8:2::2"/> | ||
| <interface hosts="r2" names="eth0" address="2001:db8:2::3"/> | ||
| <interface hosts="r2" names="eth1" address="2001:db8:4::1"/> | ||
| <interface hosts="hostB" names="eth0" address="2001:db8:4::2"/> | ||
|
|
||
| <route hosts="hostA" destination="2001:db8:4::" prefixLength="64" gateway="2001:db8:1::2" interface="eth0"/> | ||
| <route hosts="r0" destination="2001:db8:4::" prefixLength="64" gateway="2001:db8:2::2" interface="eth1"/> | ||
| <route hosts="r1" destination="2001:db8:4::" prefixLength="64" gateway="fe80::8aa:ff:fe00:8" interface="eth0"/> | ||
| <route hosts="r2" destination="2001:db8:1::" prefixLength="64" gateway="2001:db8:2::1" interface="eth0"/> | ||
| <route hosts="hostB" destination="2001:db8:1::" prefixLength="64" gateway="2001:db8:4::1" interface="eth0"/> | ||
| </config> | ||
| %#-------------------------------------------------------------------------------------------------------------- | ||
| %inifile: omnetpp.ini | ||
| [General] | ||
| record-vector-results = false | ||
| ned-path = ../../../../src;. | ||
| network = RedirectSourceNotNeighbour | ||
| sim-time-limit = 3s | ||
| cmdenv-express-mode = false | ||
| cmdenv-log-prefix = "%C: " | ||
|
|
||
| **.hasIpv4 = false | ||
| **.hasIpv6 = true | ||
| **.ipv6.configurator.networkConfiguratorModule = "configurator" | ||
| **.ipv6.neighbourDiscovery.dupAddrDetectTransmits = 0 | ||
| *.configurator.addStaticRoutes = true | ||
| *.configurator.addRemoteRoutes = false | ||
| *.configurator.addDefaultRoutes = false | ||
| *.configurator.config = xmldoc("redirect.xml") | ||
|
|
||
| *.hostA.numApps = 1 | ||
| *.hostA.app[0].typename = "PingApp" | ||
| *.hostA.app[0].destAddr = "2001:db8:4::2" | ||
| *.hostA.app[0].startTime = 2s | ||
| *.hostA.app[0].stopTime = 2.5s | ||
| *.hostA.app[0].sendInterval = 50ms | ||
|
|
||
| %#-------------------------------------------------------------------------------------------------------------- | ||
| %subst: /omnetpp::// | ||
| %#-------------------------------------------------------------------------------------------------------------- | ||
| %contains: stdout | ||
| RedirectSourceNotNeighbour.hostB.ipv6.ipv6: ICMPv6 packet: passing it to ICMPv6 module | ||
| %#-------------------------------------------------------------------------------------------------------------- | ||
| %not-contains: stdout | ||
| Sending ICMPv6 Redirect to 2001:db8:1::1 | ||
| %#-------------------------------------------------------------------------------------------------------------- | ||
| %postrun-command: grep "undisposed object:" test.out > test_undisposed.out || true | ||
| %not-contains: test_undisposed.out | ||
| undisposed object: ( | ||
| %#-------------------------------------------------------------------------------------------------------------- |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡 On-link senders lose valid redirects
When an on-link sender has a more-specific route through a gateway,
srcIsNeighbourbecomes false.doLongestPrefixMatchselects that gateway over the connected prefix, so the router never redirects that sender.Learn more
A Redirect is useful when the packet's source is on the arrival link and the router forwards the packet back out that link. doLongestPrefixMatch returns only the best matching route, so an unrelated more-specific route can hide a still-valid connected prefix. The new neighbour check then denies a Redirect to a source that is actually on-link. This can occur with manual, dynamic, or host-specific routes overlapping a connected prefix.
Example: Router R has a direct route for
2001:db8:2::/64on eth0 and a/128route for host A's2001:db8:2::10through another gateway. A sends R a packet that R forwards back onto eth0 via router B. The/128wins the lookup, and R sends no Redirect to A, although A and B share eth0.Recommended fix: Determine whether any valid on-link prefix on
fromIEcontains the source, independently of the single best forwarding route. Include directly connected static, advertised, and configured prefixes as appropriate; retain the link-local case and the original source-address guards.Was this helpful? React with 👍 or 👎 to provide feedback.