From da72504eed67674a1f5cf2e836b04a989a04d5a2 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Thu, 29 Jan 2026 18:58:32 +0100 Subject: [PATCH] core: export the CLAT state over D-Bus Export over D-Bus the CLAT state: the IPv4 and IPv6 CLAT addresses and the NAT64 prefix. --- src/core/nm-ip-config.c | 111 +++++++++++++++++++++++++++++++++++++++- src/core/nm-l3cfg.c | 11 ++++ 2 files changed, 121 insertions(+), 1 deletion(-) diff --git a/src/core/nm-ip-config.c b/src/core/nm-ip-config.c index 975ae20d45..51a069f801 100644 --- a/src/core/nm-ip-config.c +++ b/src/core/nm-ip-config.c @@ -26,6 +26,7 @@ GType nm_ip6_config_get_type(void); /*****************************************************************************/ #define NM_IP_CONFIG_ADDRESS_DATA "address-data" +#define NM_IP_CONFIG_CLAT_ADDRESS "clat-address" #define NM_IP_CONFIG_DNS_OPTIONS "dns-options" #define NM_IP_CONFIG_DNS_PRIORITY "dns-priority" #define NM_IP_CONFIG_DOMAINS "domains" @@ -41,6 +42,7 @@ NM_GOBJECT_PROPERTIES_DEFINE_FULL(_ip, NMIPConfig, PROP_IP_L3CFG, PROP_IP_ADDRESS_DATA, + PROP_IP_CLAT_ADDRESS, PROP_IP_GATEWAY, PROP_IP_ROUTE_DATA, PROP_IP_DOMAINS, @@ -164,6 +166,8 @@ get_property_ip(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec const int addr_family = nm_ip_config_get_addr_family(self); char **to_free = NULL; char sbuf_addr[NM_INET_ADDRSTRLEN]; + in_addr_t addr4; + struct in6_addr addr6; const char *const *strv; guint len; int v_i; @@ -218,6 +222,20 @@ get_property_ip(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec strv = nm_l3_config_data_get_dns_options(priv->l3cd, addr_family, &len); _value_set_variant_as(value, strv, len); break; + case PROP_IP_CLAT_ADDRESS: + if (nm_l3_config_data_get_clat_state(priv->l3cd, &addr6, NULL, NULL, &addr4)) { + if (addr_family == AF_INET) { + g_value_set_variant(value, + g_variant_new_string(nm_inet_ntop(AF_INET, &addr4, sbuf_addr))); + } else { + g_value_set_variant( + value, + g_variant_new_string(nm_inet_ntop(AF_INET6, &addr6, sbuf_addr))); + } + } else { + g_value_set_variant(value, nm_g_variant_singleton_s_empty()); + } + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; @@ -336,6 +354,13 @@ nm_ip_config_class_init(NMIPConfigClass *klass) G_VARIANT_TYPE("aa{sv}"), NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties_ip[PROP_IP_CLAT_ADDRESS] = + g_param_spec_variant(NM_IP_CONFIG_CLAT_ADDRESS, + "", + "", + G_VARIANT_TYPE("s"), + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties_ip[PROP_IP_GATEWAY] = g_param_spec_variant(NM_IP_CONFIG_GATEWAY, "", @@ -512,6 +537,9 @@ static const NMDBusInterfaceInfoExtended interface_info_ip4_config = { NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("AddressData", "aa{sv}", NM_IP_CONFIG_ADDRESS_DATA), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("ClatAddress", + "s", + NM_IP_CONFIG_CLAT_ADDRESS), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Gateway", "s", NM_IP_CONFIG_GATEWAY), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( "Routes", @@ -614,6 +642,7 @@ nm_ip4_config_class_init(NMIP4ConfigClass *klass) /*****************************************************************************/ /* public */ +#define NM_IP6_CONFIG_CLAT_PREF64 "clat-pref64" #define NM_IP6_CONFIG_NAMESERVERS "nameservers" /* deprecated */ @@ -625,6 +654,7 @@ typedef struct _NMIP6ConfigClass NMIP6ConfigClass; NM_GOBJECT_PROPERTIES_DEFINE_FULL(_ip6, NMIP6Config, + PROP_IP6_CLAT_PREF64, PROP_IP6_NAMESERVERS, PROP_IP6_ADDRESSES, PROP_IP6_ROUTES, ); @@ -651,6 +681,12 @@ static const NMDBusInterfaceInfoExtended interface_info_ip6_config = { NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("AddressData", "aa{sv}", NM_IP_CONFIG_ADDRESS_DATA), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("ClatAddress", + "s", + NM_IP_CONFIG_CLAT_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("ClatPref64", + "s", + NM_IP6_CONFIG_CLAT_PREF64), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Gateway", "s", NM_IP_CONFIG_GATEWAY), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( "Routes", @@ -682,11 +718,24 @@ get_property_ip6(GObject *object, guint prop_id, GValue *value, GParamSpec *pspe guint len; guint i; const char *const *strarr; + guint8 plen; + struct in6_addr addr6; + char sbuf[NM_UTILS_INET_ADDRSTRLEN]; switch (prop_id) { case PROP_IP6_ADDRESSES: g_value_set_variant(value, priv->v_addresses); break; + case PROP_IP6_CLAT_PREF64: + if (nm_l3_config_data_get_clat_state(priv->l3cd, NULL, &addr6, &plen, NULL)) { + nm_inet6_ntop(&addr6, sbuf); + g_value_set_variant(value, + g_variant_new_string( + nm_sprintf_bufa(NM_INET_ADDRSTRLEN + 32, "%s/%u", sbuf, plen))); + } else { + g_value_set_variant(value, nm_g_variant_singleton_s_empty()); + } + break; case PROP_IP6_ROUTES: g_value_set_variant(value, priv->v_routes); break; @@ -740,6 +789,13 @@ nm_ip6_config_class_init(NMIP6ConfigClass *klass) G_VARIANT_TYPE("a(ayuay)"), NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties_ip6[PROP_IP6_CLAT_PREF64] = + g_param_spec_variant(NM_IP6_CONFIG_CLAT_PREF64, + "", + "", + G_VARIANT_TYPE("s"), + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties_ip6[PROP_IP6_ROUTES] = g_param_spec_variant(NM_IP6_CONFIG_ROUTES, "", @@ -787,7 +843,7 @@ _handle_l3cd_changed(NMIPConfig *self, const NML3ConfigData *l3cd) const int IS_IPv4 = NM_IS_IPv4(addr_family); NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE(self); nm_auto_unref_l3cd const NML3ConfigData *l3cd_old = NULL; - GParamSpec *changed_params[8]; + GParamSpec *changed_params[10]; guint n_changed_params = 0; const char *const *strarr; const char *const *strarr_old; @@ -840,6 +896,59 @@ _handle_l3cd_changed(NMIPConfig *self, const NML3ConfigData *l3cd) } } + /* CLAT state */ + { + struct in6_addr clat_ip6; + struct in6_addr clat_pref64; + guint8 clat_pref64_plen; + in_addr_t clat_ip4; + gboolean clat_enabled; + struct in6_addr clat_ip6_old; + struct in6_addr clat_pref64_old; + guint8 clat_pref64_plen_old; + in_addr_t clat_ip4_old; + gboolean clat_enabled_old; + gboolean changed; + + clat_enabled_old = nm_l3_config_data_get_clat_state(l3cd_old, + &clat_ip6_old, + &clat_pref64_old, + &clat_pref64_plen_old, + &clat_ip4_old); + clat_enabled = nm_l3_config_data_get_clat_state(priv->l3cd, + &clat_ip6, + &clat_pref64, + &clat_pref64_plen, + &clat_ip4); + + /* CLAT address */ + if (clat_enabled != clat_enabled_old) { + changed = TRUE; + } else if (!clat_enabled) { + changed = FALSE; + } else if (IS_IPv4) { + changed = (clat_ip4 != clat_ip4_old); + } else { + changed = !IN6_ARE_ADDR_EQUAL(&clat_ip6, &clat_ip6_old); + } + if (changed) + changed_params[n_changed_params++] = obj_properties_ip[PROP_IP_CLAT_ADDRESS]; + + /* PREF64 */ + if (!IS_IPv4) { + if (clat_enabled != clat_enabled_old) { + changed = TRUE; + } else if (!clat_enabled) { + changed = FALSE; + } else { + changed = (clat_pref64_plen != clat_pref64_plen_old) + || (!IN6_ARE_ADDR_EQUAL(&clat_pref64, &clat_pref64_old)); + } + if (changed) + changed_params[n_changed_params++] = obj_properties_ip6[PROP_IP6_CLAT_PREF64]; + } + } + _notify_all(self, changed_params, n_changed_params); } diff --git a/src/core/nm-l3cfg.c b/src/core/nm-l3cfg.c index 3963173745..209ebd9c33 100644 --- a/src/core/nm-l3cfg.c +++ b/src/core/nm-l3cfg.c @@ -4351,6 +4351,17 @@ _l3cfg_update_clat_config(NML3Cfg *self, _LOGW("Couldn't find a good ipv6 route! Unable to set up CLAT!"); } } + + if (self->priv.p->clat_address_4 && self->priv.p->clat_address_6_valid) { + nm_l3_config_data_set_clat_state(l3cd, + TRUE, + &self->priv.p->clat_address_6.address, + &pref64, + pref64_plen, + self->priv.p->clat_address_4->addr); + } else { + nm_l3_config_data_set_clat_state(l3cd, FALSE, NULL, NULL, 0, INADDR_ANY); + } } #endif /* HAVE_CLAT */ }