Commit f15c4961 authored by Thomas Haller's avatar Thomas Haller

core: avoid generating reserved IPv6 interface identifiers

https://tools.ietf.org/html/rfc7217 says:

  The resulting Interface Identifier SHOULD be compared against the
  reserved IPv6 Interface Identifiers [RFC5453] [IANA-RESERVED-IID]
  and against those Interface Identifiers already employed in an
  address of the same network interface and the same network
  prefix.  In the event that an unacceptable identifier has been
  generated, this situation SHOULD be handled in the same way as
  the case of duplicate addresses (see Section 6).

In case of conflict, this suggests to create a new address incrementing
the DAD counter, etc. Don't do that. If we generate an address of the
reserved region, just rehash it right away. Note that the actual address
anyway appears random, so this re-hashing is just as good as incrementing
the DAD counter and going through the entire process again.

Note that now we no longer generate certain addresses like we did
previously. But realize that we now merely reject (1 + 16777216 + 128)
addresses out of 2^64. So, the likelyhood of of a user accidentally
generating an address that is suddenly rejected is in the order of
10e-13 (1 / 1,099,503,173,697). Which is not astronomically, but still
extreeeemely unlikely.

Also, the whole process is anyway build on the idea that somebody else
might generate conflicting addresses (DAD). It means, there was always
the extremely tiny chance that the address you generated last time is
suddenly taken by somebody else. So, this change appears to a user
like these reserved addresses are now claimed by another (non existing)
host and a different address gets generated -- business as usual, as
far as SLAAC is concerned.
parent 67da0a28
......@@ -3548,6 +3548,31 @@ nm_utils_stable_id_parse (const char *stable_id,
/*****************************************************************************/
static gboolean
_is_reserved_ipv6_iid (const guint8 *iid)
{
/* https://tools.ietf.org/html/rfc5453 */
/* https://www.iana.org/assignments/ipv6-interface-ids/ipv6-interface-ids.xml */
/* 0000:0000:0000:0000 (Subnet-Router Anycast [RFC4291]) */
if (memcmp (iid, &nm_ip_addr_zero.addr6.s6_addr[8], 8) == 0)
return TRUE;
/* 0200:5EFF:FE00:0000 - 0200:5EFF:FE00:5212 (Reserved IPv6 Interface Identifiers corresponding to the IANA Ethernet Block [RFC4291])
* 0200:5EFF:FE00:5213 (Proxy Mobile IPv6 [RFC6543])
* 0200:5EFF:FE00:5214 - 0200:5EFF:FEFF:FFFF (Reserved IPv6 Interface Identifiers corresponding to the IANA Ethernet Block [RFC4291]) */
if (memcmp (iid, (const guint8[]) { 0x02, 0x00, 0x5E, 0xFF, 0xFE }, 5) == 0)
return TRUE;
/* FDFF:FFFF:FFFF:FF80 - FDFF:FFFF:FFFF:FFFF (Reserved Subnet Anycast Addresses [RFC2526]) */
if (memcmp (iid, (const guint8[]) { 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, 7) == 0) {
if (iid[7] & 0x80)
return TRUE;
}
return FALSE;
}
static gboolean
_set_stable_privacy (NMUtilsStableType stable_type,
struct in6_addr *addr,
......@@ -3604,9 +3629,19 @@ _set_stable_privacy (NMUtilsStableType stable_type,
g_checksum_update (sum, (const guchar *) secret_key, key_len);
g_checksum_get_digest (sum, digest, &len);
g_checksum_free (sum);
g_return_val_if_fail (len == 32, FALSE);
nm_assert (len == sizeof (digest));
while (_is_reserved_ipv6_iid (digest)) {
g_checksum_reset (sum);
tmp[0] = htonl (++dad_counter);
g_checksum_update (sum, digest, len);
g_checksum_update (sum, (const guchar *) &tmp[0], sizeof (tmp[0]));
g_checksum_get_digest (sum, digest, &len);
nm_assert (len == sizeof (digest));
}
g_checksum_free (sum);
memcpy (addr->s6_addr + 8, &digest[0], 8);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment