/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2007 - 2011 Novell, Inc. * Copyright (C) 2008 - 2014 Red Hat, Inc. */ #include "nm-default.h" #include "nm-ip-config.h" #include "nm-ip4-config.h" #include "nm-ip6-config.h" #include "nm-setting-ip-config.h" #include "nm-dbus-interface.h" #include "nm-object-private.h" #include "nm-utils.h" #include "nm-core-internal.h" /*****************************************************************************/ NM_GOBJECT_PROPERTIES_DEFINE(NMIPConfig, PROP_FAMILY, PROP_GATEWAY, PROP_ADDRESSES, PROP_ROUTES, PROP_NAMESERVERS, PROP_DOMAINS, PROP_SEARCHES, PROP_WINS_SERVERS, ); typedef struct _NMIPConfigPrivate { GPtrArray *addresses; GPtrArray *routes; char ** nameservers; char ** domains; char ** searches; char ** wins_servers; char * gateway; bool addresses_new_style : 1; bool routes_new_style : 1; bool nameservers_new_style : 1; bool wins_servers_new_style : 1; } NMIPConfigPrivate; G_DEFINE_ABSTRACT_TYPE(NMIPConfig, nm_ip_config, NM_TYPE_OBJECT) #define NM_IP_CONFIG_GET_PRIVATE(self) \ _NM_GET_PRIVATE_PTR(self, NMIPConfig, NM_IS_IP_CONFIG, NMObject) /*****************************************************************************/ static NMLDBusNotifyUpdatePropFlags _notify_update_prop_addresses(NMClient * client, NMLDBusObject * dbobj, const NMLDBusMetaIface *meta_iface, guint dbus_property_idx, GVariant * value) { NMIPConfig * self = NM_IP_CONFIG(dbobj->nmobj); NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE(self); gs_unref_ptrarray GPtrArray *addresses_old = NULL; gs_unref_ptrarray GPtrArray *addresses_new = NULL; int addr_family = meta_iface == &_nml_dbus_meta_iface_nm_ip4config ? AF_INET : AF_INET6; gboolean new_style; new_style = (((const char *) meta_iface->dbus_properties[dbus_property_idx].dbus_type)[2] == '{'); if (priv->addresses_new_style) { if (!new_style) return NML_DBUS_NOTIFY_UPDATE_PROP_FLAGS_NONE; } else priv->addresses_new_style = new_style; if (value) { if (new_style) addresses_new = nm_utils_ip_addresses_from_variant(value, addr_family); else if (addr_family == AF_INET) addresses_new = nm_utils_ip4_addresses_from_variant(value, NULL); else addresses_new = nm_utils_ip6_addresses_from_variant(value, NULL); nm_assert(addresses_new); } if (!addresses_new) addresses_new = g_ptr_array_new_with_free_func((GDestroyNotify) nm_ip_address_unref); addresses_old = priv->addresses; priv->addresses = g_steal_pointer(&addresses_new); return NML_DBUS_NOTIFY_UPDATE_PROP_FLAGS_NOTIFY; } static NMLDBusNotifyUpdatePropFlags _notify_update_prop_routes(NMClient * client, NMLDBusObject * dbobj, const NMLDBusMetaIface *meta_iface, guint dbus_property_idx, GVariant * value) { NMIPConfig * self = NM_IP_CONFIG(dbobj->nmobj); NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE(self); gs_unref_ptrarray GPtrArray *routes_old = NULL; gs_unref_ptrarray GPtrArray *routes_new = NULL; int addr_family = meta_iface == &_nml_dbus_meta_iface_nm_ip4config ? AF_INET : AF_INET6; gboolean new_style; new_style = (((const char *) meta_iface->dbus_properties[dbus_property_idx].dbus_type)[2] == '{'); if (priv->routes_new_style) { if (!new_style) return NML_DBUS_NOTIFY_UPDATE_PROP_FLAGS_NONE; } else priv->routes_new_style = new_style; if (value) { if (new_style) routes_new = nm_utils_ip_routes_from_variant(value, addr_family); else if (addr_family == AF_INET) routes_new = nm_utils_ip4_routes_from_variant(value); else routes_new = nm_utils_ip6_routes_from_variant(value); nm_assert(routes_new); } if (!routes_new) routes_new = g_ptr_array_new_with_free_func((GDestroyNotify) nm_ip_route_unref); routes_old = priv->routes; priv->routes = g_steal_pointer(&routes_new); return NML_DBUS_NOTIFY_UPDATE_PROP_FLAGS_NOTIFY; } static NMLDBusNotifyUpdatePropFlags _notify_update_prop_nameservers(NMClient * client, NMLDBusObject * dbobj, const NMLDBusMetaIface *meta_iface, guint dbus_property_idx, GVariant * value) { NMIPConfig * self = NM_IP_CONFIG(dbobj->nmobj); NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE(self); gs_strfreev char **nameservers_new = NULL; gboolean new_style = TRUE; int addr_family = meta_iface == &_nml_dbus_meta_iface_nm_ip4config ? AF_INET : AF_INET6; if (addr_family == AF_INET) { new_style = (((const char *) meta_iface->dbus_properties[dbus_property_idx].dbus_type)[1] == 'a'); if (priv->nameservers_new_style) { if (!new_style) return NML_DBUS_NOTIFY_UPDATE_PROP_FLAGS_NONE; } else priv->nameservers_new_style = new_style; } if (value) { if (addr_family == AF_INET6) nameservers_new = nm_utils_ip6_dns_from_variant(value); else if (!new_style) nameservers_new = nm_utils_ip4_dns_from_variant(value); else { GVariantIter iter; GVariantIter * iter_v; gs_unref_ptrarray GPtrArray *arr = NULL; g_variant_iter_init(&iter, value); while (g_variant_iter_next(&iter, "a{sv}", &iter_v)) { const char *key; GVariant * val; while (g_variant_iter_next(iter_v, "{&sv}", &key, &val)) { if (nm_streq(key, "address")) { gs_free char *val_str = NULL; if (!g_variant_is_of_type(val, G_VARIANT_TYPE_STRING)) goto next; if (!nm_utils_parse_inaddr(AF_INET, g_variant_get_string(val, NULL), &val_str)) goto next; if (!arr) arr = g_ptr_array_new(); g_ptr_array_add(arr, g_steal_pointer(&val_str)); goto next; } next: g_variant_unref(val); } g_variant_iter_free(iter_v); } if (arr && arr->len > 0) nameservers_new = nm_utils_strv_dup((char **) arr->pdata, arr->len, FALSE); else nameservers_new = g_new0(char *, 1); } nm_assert(nameservers_new); } g_strfreev(priv->nameservers); priv->nameservers = g_steal_pointer(&nameservers_new); return NML_DBUS_NOTIFY_UPDATE_PROP_FLAGS_NOTIFY; } static NMLDBusNotifyUpdatePropFlags _notify_update_prop_wins_servers(NMClient * client, NMLDBusObject * dbobj, const NMLDBusMetaIface *meta_iface, guint dbus_property_idx, GVariant * value) { NMIPConfig * self = NM_IP_CONFIG(dbobj->nmobj); NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE(self); gs_strfreev char **wins_servers_new = NULL; gboolean new_style; new_style = (((const char *) meta_iface->dbus_properties[dbus_property_idx].dbus_type)[1] == 's'); if (priv->wins_servers_new_style) { if (!new_style) return NML_DBUS_NOTIFY_UPDATE_PROP_FLAGS_NONE; } else priv->wins_servers_new_style = new_style; if (value) { if (new_style) wins_servers_new = g_variant_dup_strv(value, NULL); else wins_servers_new = nm_utils_ip4_dns_from_variant(value); nm_assert(wins_servers_new); } g_strfreev(priv->wins_servers); priv->wins_servers = g_steal_pointer(&wins_servers_new); return NML_DBUS_NOTIFY_UPDATE_PROP_FLAGS_NOTIFY; } /*****************************************************************************/ static void get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { NMIPConfig *self = NM_IP_CONFIG(object); switch (prop_id) { case PROP_FAMILY: g_value_set_int(value, nm_ip_config_get_family(self)); break; case PROP_GATEWAY: g_value_set_string(value, nm_ip_config_get_gateway(self)); break; case PROP_ADDRESSES: g_value_take_boxed(value, _nm_utils_copy_array(nm_ip_config_get_addresses(self), (NMUtilsCopyFunc) nm_ip_address_dup, (GDestroyNotify) nm_ip_address_unref)); break; case PROP_ROUTES: g_value_take_boxed(value, _nm_utils_copy_array(nm_ip_config_get_routes(self), (NMUtilsCopyFunc) nm_ip_route_dup, (GDestroyNotify) nm_ip_route_unref)); break; case PROP_NAMESERVERS: g_value_set_boxed(value, (char **) nm_ip_config_get_nameservers(self)); break; case PROP_DOMAINS: g_value_set_boxed(value, (char **) nm_ip_config_get_domains(self)); break; case PROP_SEARCHES: g_value_set_boxed(value, (char **) nm_ip_config_get_searches(self)); break; case PROP_WINS_SERVERS: g_value_set_boxed(value, (char **) nm_ip_config_get_wins_servers(self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } /*****************************************************************************/ static void nm_ip_config_init(NMIPConfig *self) { NMIPConfigPrivate *priv; priv = G_TYPE_INSTANCE_GET_PRIVATE(self, NM_TYPE_IP_CONFIG, NMIPConfigPrivate); self->_priv = priv; priv->addresses = g_ptr_array_new_with_free_func((GDestroyNotify) nm_ip_address_unref); priv->routes = g_ptr_array_new_with_free_func((GDestroyNotify) nm_ip_route_unref); } static void finalize(GObject *object) { NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE(object); g_free(priv->gateway); g_ptr_array_unref(priv->routes); g_ptr_array_unref(priv->addresses); g_strfreev(priv->nameservers); g_strfreev(priv->domains); g_strfreev(priv->searches); g_strfreev(priv->wins_servers); G_OBJECT_CLASS(nm_ip_config_parent_class)->finalize(object); } const NMLDBusMetaIface _nml_dbus_meta_iface_nm_ip4config = NML_DBUS_META_IFACE_INIT_PROP( NM_DBUS_INTERFACE_IP4_CONFIG, nm_ip4_config_get_type, NML_DBUS_META_INTERFACE_PRIO_INSTANTIATE_HIGH, NML_DBUS_META_IFACE_DBUS_PROPERTIES( NML_DBUS_META_PROPERTY_INIT_FCN("AddressData", PROP_ADDRESSES, "aa{sv}", _notify_update_prop_addresses), NML_DBUS_META_PROPERTY_INIT_FCN("Addresses", PROP_ADDRESSES, "aau", _notify_update_prop_addresses, .obj_property_no_reverse_idx = TRUE), NML_DBUS_META_PROPERTY_INIT_TODO("DnsOptions", "as"), NML_DBUS_META_PROPERTY_INIT_TODO("DnsPriority", "i"), NML_DBUS_META_PROPERTY_INIT_AS("Domains", PROP_DOMAINS, NMIPConfigPrivate, domains), NML_DBUS_META_PROPERTY_INIT_S("Gateway", PROP_GATEWAY, NMIPConfigPrivate, gateway), NML_DBUS_META_PROPERTY_INIT_FCN("NameserverData", PROP_NAMESERVERS, "aa{sv}", _notify_update_prop_nameservers), NML_DBUS_META_PROPERTY_INIT_FCN("Nameservers", PROP_NAMESERVERS, "au", _notify_update_prop_nameservers, .obj_property_no_reverse_idx = TRUE), NML_DBUS_META_PROPERTY_INIT_FCN("RouteData", PROP_ROUTES, "aa{sv}", _notify_update_prop_routes), NML_DBUS_META_PROPERTY_INIT_FCN("Routes", PROP_ROUTES, "aau", _notify_update_prop_routes, .obj_property_no_reverse_idx = TRUE), NML_DBUS_META_PROPERTY_INIT_AS("Searches", PROP_SEARCHES, NMIPConfigPrivate, searches), NML_DBUS_META_PROPERTY_INIT_FCN("WinsServerData", PROP_WINS_SERVERS, "as", _notify_update_prop_wins_servers), NML_DBUS_META_PROPERTY_INIT_FCN("WinsServers", PROP_WINS_SERVERS, "au", _notify_update_prop_wins_servers, .obj_property_no_reverse_idx = TRUE), ), .base_struct_offset = G_STRUCT_OFFSET(NMIPConfig, _priv), ); const NMLDBusMetaIface _nml_dbus_meta_iface_nm_ip6config = NML_DBUS_META_IFACE_INIT_PROP( NM_DBUS_INTERFACE_IP6_CONFIG, nm_ip6_config_get_type, NML_DBUS_META_INTERFACE_PRIO_INSTANTIATE_HIGH, NML_DBUS_META_IFACE_DBUS_PROPERTIES( NML_DBUS_META_PROPERTY_INIT_FCN("AddressData", PROP_ADDRESSES, "aa{sv}", _notify_update_prop_addresses), NML_DBUS_META_PROPERTY_INIT_FCN("Addresses", PROP_ADDRESSES, "a(ayuay)", _notify_update_prop_addresses, .obj_property_no_reverse_idx = TRUE), NML_DBUS_META_PROPERTY_INIT_TODO("DnsOptions", "as"), NML_DBUS_META_PROPERTY_INIT_TODO("DnsPriority", "i"), NML_DBUS_META_PROPERTY_INIT_AS("Domains", PROP_DOMAINS, NMIPConfigPrivate, domains), NML_DBUS_META_PROPERTY_INIT_S("Gateway", PROP_GATEWAY, NMIPConfigPrivate, gateway), NML_DBUS_META_PROPERTY_INIT_FCN("Nameservers", PROP_NAMESERVERS, "aay", _notify_update_prop_nameservers), NML_DBUS_META_PROPERTY_INIT_FCN("RouteData", PROP_ROUTES, "aa{sv}", _notify_update_prop_routes), NML_DBUS_META_PROPERTY_INIT_FCN("Routes", PROP_ROUTES, "a(ayuayu)", _notify_update_prop_routes, .obj_property_no_reverse_idx = TRUE), NML_DBUS_META_PROPERTY_INIT_AS("Searches", PROP_SEARCHES, NMIPConfigPrivate, searches), ), .base_struct_offset = G_STRUCT_OFFSET(NMIPConfig, _priv), ); static void nm_ip_config_class_init(NMIPConfigClass *config_class) { GObjectClass *object_class = G_OBJECT_CLASS(config_class); g_type_class_add_private(config_class, sizeof(NMIPConfigPrivate)); object_class->get_property = get_property; object_class->finalize = finalize; /** * NMIPConfig:family: * * The IP address family of the configuration; either * AF_INET or AF_INET6. **/ obj_properties[PROP_FAMILY] = g_param_spec_int(NM_IP_CONFIG_FAMILY, "", "", 0, 255, AF_UNSPEC, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); /** * NMIPConfig:gateway: * * The IP gateway address of the configuration as string. **/ obj_properties[PROP_GATEWAY] = g_param_spec_string(NM_IP_CONFIG_GATEWAY, "", "", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); /** * NMIPConfig:addresses: * * A #GPtrArray containing the addresses (#NMIPAddress) of the configuration. **/ obj_properties[PROP_ADDRESSES] = g_param_spec_boxed(NM_IP_CONFIG_ADDRESSES, "", "", G_TYPE_PTR_ARRAY, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); /** * NMIPConfig:routes: (type GPtrArray(NMIPRoute)) * * A #GPtrArray containing the routes (#NMIPRoute) of the configuration. **/ obj_properties[PROP_ROUTES] = g_param_spec_boxed(NM_IP_CONFIG_ROUTES, "", "", G_TYPE_PTR_ARRAY, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); /** * NMIPConfig:nameservers: * * The array containing name server IP addresses of the configuration. **/ obj_properties[PROP_NAMESERVERS] = g_param_spec_boxed(NM_IP_CONFIG_NAMESERVERS, "", "", G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); /** * NMIPConfig:domains: * * The array containing domain strings of the configuration. **/ obj_properties[PROP_DOMAINS] = g_param_spec_boxed(NM_IP_CONFIG_DOMAINS, "", "", G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); /** * NMIPConfig:searches: * * The array containing DNS search strings of the configuration. **/ obj_properties[PROP_SEARCHES] = g_param_spec_boxed(NM_IP_CONFIG_SEARCHES, "", "", G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); /** * NMIPConfig:wins-servers: * * The array containing WINS server IP addresses of the configuration. * (This will always be empty for IPv6 configurations.) **/ obj_properties[PROP_WINS_SERVERS] = g_param_spec_boxed(NM_IP_CONFIG_WINS_SERVERS, "", "", G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); _nml_dbus_meta_class_init_with_properties(object_class, &_nml_dbus_meta_iface_nm_ip4config, &_nml_dbus_meta_iface_nm_ip6config); } /** * nm_ip_config_get_family: * @config: a #NMIPConfig * * Gets the IP address family * * Returns: the IP address family; either AF_INET or * AF_INET6 **/ int nm_ip_config_get_family(NMIPConfig *config) { g_return_val_if_fail(NM_IS_IP_CONFIG(config), AF_UNSPEC); return NM_IS_IP4_CONFIG(config) ? AF_INET : AF_INET6; } /** * nm_ip_config_get_gateway: * @config: a #NMIPConfig * * Gets the IP gateway address. * * Returns: (transfer none): the IP address of the gateway. **/ const char * nm_ip_config_get_gateway(NMIPConfig *config) { g_return_val_if_fail(NM_IS_IP_CONFIG(config), NULL); return _nml_coerce_property_str_not_empty(NM_IP_CONFIG_GET_PRIVATE(config)->gateway); } /** * nm_ip_config_get_addresses: * @config: a #NMIPConfig * * Gets the IP addresses (containing the address, prefix, and gateway). * * Returns: (element-type NMIPAddress) (transfer none): the #GPtrArray * containing #NMIPAddresses. This is the internal copy used by the * configuration and must not be modified. The library never modifies the * returned array and thus it is safe for callers to reference and keep using it. **/ GPtrArray * nm_ip_config_get_addresses(NMIPConfig *config) { g_return_val_if_fail(NM_IS_IP_CONFIG(config), NULL); return NM_IP_CONFIG_GET_PRIVATE(config)->addresses; } /** * nm_ip_config_get_nameservers: * @config: a #NMIPConfig * * Gets the domain name servers (DNS). * * Returns: (transfer none): the array of nameserver IP addresses **/ const char *const * nm_ip_config_get_nameservers(NMIPConfig *config) { g_return_val_if_fail(NM_IS_IP_CONFIG(config), NULL); return _nml_coerce_property_strv_not_null(NM_IP_CONFIG_GET_PRIVATE(config)->nameservers); } /** * nm_ip_config_get_domains: * @config: a #NMIPConfig * * Gets the domain names. * * Returns: (transfer none): the array of domains. * (This is never %NULL, though it may be 0-length). **/ const char *const * nm_ip_config_get_domains(NMIPConfig *config) { g_return_val_if_fail(NM_IS_IP_CONFIG(config), NULL); return _nml_coerce_property_strv_not_null(NM_IP_CONFIG_GET_PRIVATE(config)->domains); } /** * nm_ip_config_get_searches: * @config: a #NMIPConfig * * Gets the DNS searches. * * Returns: (transfer none): the array of DNS search strings. * (This is never %NULL, though it may be 0-length). **/ const char *const * nm_ip_config_get_searches(NMIPConfig *config) { g_return_val_if_fail(NM_IS_IP_CONFIG(config), NULL); return _nml_coerce_property_strv_not_null(NM_IP_CONFIG_GET_PRIVATE(config)->searches); } /** * nm_ip_config_get_wins_servers: * @config: a #NMIPConfig * * Gets the Windows Internet Name Service servers (WINS). * * Returns: (transfer none): the arry of WINS server IP address strings. * (This is never %NULL, though it may be 0-length.) **/ const char *const * nm_ip_config_get_wins_servers(NMIPConfig *config) { g_return_val_if_fail(NM_IS_IP_CONFIG(config), NULL); return _nml_coerce_property_strv_not_null(NM_IP_CONFIG_GET_PRIVATE(config)->wins_servers); } /** * nm_ip_config_get_routes: * @config: a #NMIPConfig * * Gets the routes. * * Returns: (element-type NMIPRoute) (transfer none): the #GPtrArray containing * #NMIPRoutes. This is the internal copy used by the configuration, and must * not be modified. The library never modifies the returned array and thus it is * safe for callers to reference and keep using it. * **/ GPtrArray * nm_ip_config_get_routes(NMIPConfig *config) { g_return_val_if_fail(NM_IS_IP_CONFIG(config), NULL); return NM_IP_CONFIG_GET_PRIVATE(config)->routes; }