mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-03-22 11:30:35 +01:00
l3cfg: fix selection of the CLAT IPv6 prefix
If the router advertises both ULA and GUA prefixes, the CLAT should
select the one that better matches the NAT64 prefix when generating
the additional IPv6 address, as recommended by Internet Draft
draft-ietf-v6ops-claton.
The current implementation just takes the first one, which can cause
problems. For example, if the network is using a public NAT64 server,
the NAT64 prefix is in the GUA range. Choosing a ULA as source address
would not work.
Fixes: f0e77a4354 ('Add support for CLAT to l3cfg')
This commit is contained in:
parent
7f2745f3b1
commit
a03a245819
1 changed files with 74 additions and 19 deletions
|
|
@ -4140,6 +4140,53 @@ update_routes:
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* _clat_prefix_is_better:
|
||||
* @best: current best candidate (or %NULL)
|
||||
* @candidate: the new candidate prefix
|
||||
* @nat64_pref: the NAT64 prefix
|
||||
*
|
||||
* Compare two SLAAC candidate prefixes to be used for CLAT,
|
||||
* as recommended by draft-ietf-v6ops-claton Section 7. Apply
|
||||
* rules 6 and 8 of the source address selection algorithm from
|
||||
* RFC 6724, Section 5.
|
||||
*
|
||||
* Returns %TRUE if @candidate is better than @best.
|
||||
*/
|
||||
static gboolean
|
||||
_clat_prefix_is_better(const NMPlatformIP6Address *best,
|
||||
const NMPlatformIP6Address *candidate,
|
||||
const struct in6_addr *nat64_pref)
|
||||
{
|
||||
guint nat64_pref_label;
|
||||
gboolean best_label_match;
|
||||
gboolean cand_label_match;
|
||||
guint best_prefix_len;
|
||||
guint cand_prefix_len;
|
||||
|
||||
if (!best)
|
||||
return TRUE;
|
||||
|
||||
/* Rule 6: prefer the address whose RFC 6724 label matches
|
||||
* the label of the NAT64 prefix. */
|
||||
nat64_pref_label = nm_ip6_addr_rfc6724_label(nat64_pref);
|
||||
best_label_match = nm_ip6_addr_rfc6724_label(&best->address) == nat64_pref_label;
|
||||
cand_label_match = nm_ip6_addr_rfc6724_label(&candidate->address) == nat64_pref_label;
|
||||
|
||||
if (cand_label_match && !best_label_match)
|
||||
return TRUE;
|
||||
else if (best_label_match && !cand_label_match)
|
||||
return FALSE;
|
||||
|
||||
/* Rule 8: longest matching prefix with the NAT64 prefix. */
|
||||
best_prefix_len = nm_ip6_addr_common_prefix_len(&best->address, nat64_pref);
|
||||
cand_prefix_len = nm_ip6_addr_common_prefix_len(&candidate->address, nat64_pref);
|
||||
if (cand_prefix_len != best_prefix_len)
|
||||
return cand_prefix_len > best_prefix_len;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
_l3cfg_update_clat_config(NML3Cfg *self,
|
||||
NML3ConfigData *l3cd,
|
||||
|
|
@ -4206,29 +4253,37 @@ _l3cfg_update_clat_config(NML3Cfg *self,
|
|||
network_id = nm_l3_config_data_get_network_id(l3cd);
|
||||
|
||||
if (!self->priv.p->clat_address_6_valid && network_id) {
|
||||
const NMPlatformIP6Address *best_prefix = NULL;
|
||||
|
||||
/* Select the best SLAAC prefix for the CLAT address per
|
||||
* draft-ietf-v6ops-claton-14 Section 7 */
|
||||
nm_l3_config_data_iter_ip6_address_for_each (&iter, l3cd, &ip6_entry) {
|
||||
if (ip6_entry->addr_source == NM_IP_CONFIG_SOURCE_NDISC && ip6_entry->plen == 64) {
|
||||
ip6 = ip6_entry->address;
|
||||
|
||||
nm_utils_ipv6_addr_set_stable_privacy(NM_UTILS_STABLE_TYPE_CLAT,
|
||||
&ip6,
|
||||
nm_l3cfg_get_ifname(self, TRUE),
|
||||
network_id,
|
||||
0);
|
||||
self->priv.p->clat_address_6 = (NMPlatformIP6Address) {
|
||||
.ifindex = self->priv.ifindex,
|
||||
.address = ip6,
|
||||
.peer_address = ip6,
|
||||
.addr_source = NM_IP_CONFIG_SOURCE_CLAT,
|
||||
.plen = ip6_entry->plen,
|
||||
};
|
||||
|
||||
_LOGT("clat: using IPv6 address %s", nm_inet6_ntop(&ip6, buf));
|
||||
|
||||
self->priv.p->clat_address_6_valid = TRUE;
|
||||
break;
|
||||
if (_clat_prefix_is_better(best_prefix, ip6_entry, &pref64))
|
||||
best_prefix = ip6_entry;
|
||||
}
|
||||
}
|
||||
|
||||
if (best_prefix) {
|
||||
ip6 = best_prefix->address;
|
||||
|
||||
nm_utils_ipv6_addr_set_stable_privacy(NM_UTILS_STABLE_TYPE_CLAT,
|
||||
&ip6,
|
||||
nm_l3cfg_get_ifname(self, TRUE),
|
||||
network_id,
|
||||
0);
|
||||
self->priv.p->clat_address_6 = (NMPlatformIP6Address) {
|
||||
.ifindex = self->priv.ifindex,
|
||||
.address = ip6,
|
||||
.peer_address = ip6,
|
||||
.addr_source = NM_IP_CONFIG_SOURCE_CLAT,
|
||||
.plen = best_prefix->plen,
|
||||
};
|
||||
|
||||
_LOGT("clat: using IPv6 address %s", nm_inet6_ntop(&ip6, buf));
|
||||
|
||||
self->priv.p->clat_address_6_valid = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't get a v4 address if we have no v6 address (otherwise, we could
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue