summaryrefslogtreecommitdiff
path: root/sys/netinet6
diff options
context:
space:
mode:
authorFlorian Obser <florian@cvs.openbsd.org>2020-08-07 18:09:17 +0000
committerFlorian Obser <florian@cvs.openbsd.org>2020-08-07 18:09:17 +0000
commit94b260d1be63a4c20225d69f039dad7a8ca7b5b1 (patch)
tree8181a0aa899cfa316862d0b3e72bbacc00647fa0 /sys/netinet6
parentf2cb2908e9c3ae4f026113c83826fcd6f0f4ad90 (diff)
The IPv6 source address selection rewrite had one (known) difference
to the previous behavior: In case of a tie the new implementation would keep the current best address while the old implementation replaced the best address. Since IPv6 addresses are stored in a TAILQ this meant that the rewrite would use the "oldest" address while the previous behavior was to use the "newest". RFC 6724 section 5 has no opinion which one is better and leaves the tie break up to implementers. naddy found out the hard way that this breaks his IPv6 connectivity in case of flash renumbering events when the link on his cpe flaps and a new prefix is used since we would always pick an old address. While we could pick the newest address in a tie break this feels too much like an implementation detail, a solution much more in the spirit of IPv6 is to pick the address with the highest preferred lifetime (or valid lifetime in case of another tie). very patient testing naddy@
Diffstat (limited to 'sys/netinet6')
-rw-r--r--sys/netinet6/in6.c35
1 files changed, 33 insertions, 2 deletions
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
index cbc7ccc9bcd..f26eed31bdd 100644
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: in6.c,v 1.241 2020/08/04 17:05:52 anton Exp $ */
+/* $OpenBSD: in6.c,v 1.242 2020/08/07 18:09:16 florian Exp $ */
/* $KAME: in6.c,v 1.372 2004/06/14 08:14:21 itojun Exp $ */
/*
@@ -1498,7 +1498,38 @@ in6_ifawithscope(struct ifnet *oifp, struct in6_addr *dst, u_int rdomain)
continue;
#endif
goto replace;
- }
+ } else if (tlen < blen)
+ continue;
+
+ /*
+ * If the eight rules fail to choose a single address,
+ * the tiebreaker is implementation-specific.
+ */
+
+ /* Prefer address with highest pltime. */
+ if (ia6_best->ia6_updatetime +
+ ia6_best->ia6_lifetime.ia6t_pltime <
+ ifatoia6(ifa)->ia6_updatetime +
+ ifatoia6(ifa)->ia6_lifetime.ia6t_pltime)
+ goto replace;
+ else if (ia6_best->ia6_updatetime +
+ ia6_best->ia6_lifetime.ia6t_pltime >
+ ifatoia6(ifa)->ia6_updatetime +
+ ifatoia6(ifa)->ia6_lifetime.ia6t_pltime)
+ continue;
+
+ /* Prefer address with highest vltime. */
+ if (ia6_best->ia6_updatetime +
+ ia6_best->ia6_lifetime.ia6t_vltime <
+ ifatoia6(ifa)->ia6_updatetime +
+ ifatoia6(ifa)->ia6_lifetime.ia6t_vltime)
+ goto replace;
+ else if (ia6_best->ia6_updatetime +
+ ia6_best->ia6_lifetime.ia6t_vltime >
+ ifatoia6(ifa)->ia6_updatetime +
+ ifatoia6(ifa)->ia6_lifetime.ia6t_vltime)
+ continue;
+
continue;
replace:
ia6_best = ifatoia6(ifa);