git: 41399ce61bcc - main - inet6: RFC 8981 SLAAC Temporary Address Extensions
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 20 Jun 2025 16:17:03 UTC
The branch main has been updated by des:
URL: https://cgit.FreeBSD.org/src/commit/?id=41399ce61bcc56711cba3fed1ab5b4e72c937576
commit 41399ce61bcc56711cba3fed1ab5b4e72c937576
Author: Marek Zarychta <zarychtam@plan-b.pwste.edu.pl>
AuthorDate: 2025-05-17 06:56:20 +0000
Commit: Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2025-06-20 16:16:21 +0000
inet6: RFC 8981 SLAAC Temporary Address Extensions
Deprecate the use of MD5 as the algorithm for generating temporary
interface identifiers (IIDs) for IPv6 addresses, improving cryptographic
robustness.
Introduce per-address randomized IIDs, ensuring that each temporary
address uses a distinct interface identifier to enhance privacy and
avoid correlation across addresses.
Update the IID generation logic to respect the Reserved IPv6 Interface
Identifiers list.
Enhance sysctl_ip6_temppltime() so that ip6_temp_max_desync_factor is
dynamically recalculated whenever ip6_temp_preferred_lifetime is updated
via sysctl. This ensures that MAX_DESYNC_FACTOR remains approximately
1/32 of the preferred lifetime plus 10 minutes. DESYNC_FACTOR is also
regenerated after each update.
Timers related to temporary address regeneration were updated to match
the design recommendations in RFC 8981.
A new read-only sysctl variable net.inet6.ip6.temp_max_desync_factor
is introduced to expose the computed value of MAX_DESYNC_FACTOR to
userland for observability and debugging.
Input validation to reject temppltime values too small or too large is
included.
This all brings the temporary address lifetime handling closer to the
intended design in RFC 8981 and improves robustness against
misconfiguration.
PR: 245103
MFC after: 1 month
Differential Revision: https://reviews.freebsd.org/D50108
---
sys/netinet6/in6_proto.c | 8 ++++++--
sys/netinet6/ip6_input.c | 10 +++++++++-
sys/netinet6/nd6.h | 4 +++-
sys/netinet6/nd6_rtr.c | 3 ++-
4 files changed, 20 insertions(+), 5 deletions(-)
diff --git a/sys/netinet6/in6_proto.c b/sys/netinet6/in6_proto.c
index 8541e19eebf8..b289d4eeb0a2 100644
--- a/sys/netinet6/in6_proto.c
+++ b/sys/netinet6/in6_proto.c
@@ -217,15 +217,19 @@ SYSCTL_NODE(_net_inet6, IPPROTO_ESP, ipsec6, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
static int
sysctl_ip6_temppltime(SYSCTL_HANDLER_ARGS)
{
- int error, val;
+ int error, val, ndf;
val = V_ip6_temp_preferred_lifetime;
error = sysctl_handle_int(oidp, &val, 0, req);
if (error != 0 || !req->newptr)
return (error);
- if (val < V_ip6_desync_factor + V_ip6_temp_regen_advance)
+ ndf = TEMP_MAX_DESYNC_FACTOR_BASE + (val >> 2) + (val >> 3);
+ if (val < ndf + V_ip6_temp_regen_advance ||
+ val > V_ip6_temp_valid_lifetime)
return (EINVAL);
V_ip6_temp_preferred_lifetime = val;
+ V_ip6_temp_max_desync_factor = ndf;
+ V_ip6_desync_factor = arc4random() % ndf;
return (0);
}
diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c
index 68e4be66537b..45fd23ea6c21 100644
--- a/sys/netinet6/ip6_input.c
+++ b/sys/netinet6/ip6_input.c
@@ -173,6 +173,11 @@ SYSCTL_BOOL(_net_inet6_ip6, OID_AUTO, source_address_validation,
CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_sav), true,
"Drop incoming packets with source address that is a local address");
+SYSCTL_UINT(_net_inet6_ip6, OID_AUTO, temp_max_desync_factor,
+ CTLFLAG_RD | CTLFLAG_VNET,
+ &VNET_NAME(ip6_temp_max_desync_factor), 0,
+ "RFC 8981 max desync factor");
+
#ifdef RSS
static struct netisr_handler ip6_direct_nh = {
.nh_name = "ip6_direct",
@@ -262,7 +267,10 @@ ip6_vnet_init(void *arg __unused)
nd6_init();
frag6_init();
- V_ip6_desync_factor = arc4random() % MAX_TEMP_DESYNC_FACTOR;
+ V_ip6_temp_max_desync_factor = TEMP_MAX_DESYNC_FACTOR_BASE +
+ (V_ip6_temp_preferred_lifetime >> 2) +
+ (V_ip6_temp_preferred_lifetime >> 3);
+ V_ip6_desync_factor = arc4random() % V_ip6_temp_max_desync_factor;
/* Skip global initialization stuff for non-default instances. */
#ifdef VIMAGE
diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h
index f8cf99cf09ac..9cb2571da58b 100644
--- a/sys/netinet6/nd6.h
+++ b/sys/netinet6/nd6.h
@@ -187,7 +187,7 @@ struct in6_ndifreq {
#define DEF_TEMP_VALID_LIFETIME 172800 /* 2 days */
#define DEF_TEMP_PREFERRED_LIFETIME 86400 /* 1 day */
#define TEMPADDR_REGEN_ADVANCE 5 /* sec */
-#define MAX_TEMP_DESYNC_FACTOR 600 /* 10 min */
+#define TEMP_MAX_DESYNC_FACTOR_BASE 300 /* 5 min */
#define ND_COMPUTE_RTIME(x) \
(((MIN_RANDOM_FACTOR * (x >> 10)) + (arc4random() & \
((MAX_RANDOM_FACTOR - MIN_RANDOM_FACTOR) * (x >> 10)))) /1000)
@@ -292,11 +292,13 @@ VNET_DECLARE(struct mtx, nd6_onlink_mtx);
/* nd6_rtr.c */
VNET_DECLARE(int, nd6_defifindex);
VNET_DECLARE(int, ip6_desync_factor); /* seconds */
+VNET_DECLARE(uint32_t, ip6_temp_max_desync_factor); /* seconds */
VNET_DECLARE(u_int32_t, ip6_temp_preferred_lifetime); /* seconds */
VNET_DECLARE(u_int32_t, ip6_temp_valid_lifetime); /* seconds */
VNET_DECLARE(int, ip6_temp_regen_advance); /* seconds */
#define V_nd6_defifindex VNET(nd6_defifindex)
#define V_ip6_desync_factor VNET(ip6_desync_factor)
+#define V_ip6_temp_max_desync_factor VNET(ip6_temp_max_desync_factor)
#define V_ip6_temp_preferred_lifetime VNET(ip6_temp_preferred_lifetime)
#define V_ip6_temp_valid_lifetime VNET(ip6_temp_valid_lifetime)
#define V_ip6_temp_regen_advance VNET(ip6_temp_regen_advance)
diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c
index d9edb0d3e930..b9af0a78a584 100644
--- a/sys/netinet6/nd6_rtr.c
+++ b/sys/netinet6/nd6_rtr.c
@@ -94,6 +94,7 @@ VNET_DEFINE(int, nd6_defifindex);
VNET_DEFINE(int, ip6_use_tempaddr) = 0;
VNET_DEFINE(int, ip6_desync_factor);
+VNET_DEFINE(uint32_t, ip6_temp_max_desync_factor) = TEMP_MAX_DESYNC_FACTOR_BASE;
VNET_DEFINE(u_int32_t, ip6_temp_preferred_lifetime) = DEF_TEMP_PREFERRED_LIFETIME;
VNET_DEFINE(u_int32_t, ip6_temp_valid_lifetime) = DEF_TEMP_VALID_LIFETIME;
@@ -2229,7 +2230,7 @@ restart:
/*
* Get a randomized interface identifier for a temporary address
- * <draft-ietf-6man-rfc4941bis-08.txt>, Section 3.3.1.
+ * Based on RFC 8981, Section 3.3.1.
*/
static int
in6_get_tmp_ifid(struct in6_aliasreq *ifra)