Assume a scenario with something like the following routes:
default via fe80::1 dev dummy0
2001:db8:1::/48 via fe80::10 dev dummy0
2001:db8:1::/48 from 2001:db8:1:2::/64 via fe80::12 dev dummy0
Now if a lookup happens for 2001:db8:1::2345, but with a source address
*not* covered by the third route, the expectation is to hit the second
one. Unfortunately, this was broken since the code, on failing the
lookup in the subtree, didn't consider the node itself which the subtree
is attached to, i.e. route #2 above.
The fix is simple, check if the subtree is attached to a node that is
itself a valid route before backtracking to less specific destination
prefixes.
This case is somewhat rare for several reasons. To begin with, subtree
routes are most commonly attached to the default destination.
Additionally, in the rare cases where a non-default destination prefix
is host to subtree routes, the fallback on not hitting any subtree route
is commonly a default route (or a subtree route on that).
(Note that this was working for the "::/0 from ::/0" case since the root
node is special-cased. The issue was discovered during RFC 6724 rule
5.5 testing, trying to find edge cases.)
Signed-off-by: David 'equinox' Lamparter <redacted>
Cc: Paolo Abeni <pabeni@redhat.com>
Cc: Lorenzo Colitti <redacted>
Cc: Patrick Rohr <redacted>
Cc: Maciej Żenczykowski <redacted>
---
net/ipv6/ip6_fib.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index a130cdfaebfb..273f2bfc5286 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -1656,8 +1656,11 @@ static struct fib6_node *fib6_node_lookup_1(struct fib6_node *root,
struct fib6_node *sfn;
sfn = fib6_node_lookup_1(subtree,
args + 1);
- if (!sfn)
+ if (!sfn) {
+ if (fn->fn_flags & RTN_RTINFO)
+ return fn;
goto backtrack;
+ }
fn = sfn;
}
#endif--
2.53.0