From ddfa3544004169716a75a3d6b734e29332b47015 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 15 May 2015 15:00:07 +0200 Subject: [PATCH 1/8] device: add nm_device_get_type_description() function Add a function to get a concise representation of the device type. libnm already has nm_device_get_type_description() for that and it is shown by nmcli -f GENERAL.TYPE device show Reimplement that function for nm-core. Just take care that the two implementations don't diverge. (cherry picked from commit e9e9d44468de460afaa11865bae321145b78212e) --- libnm/nm-device.c | 3 +++ src/devices/nm-device-generic.c | 9 ++++++++ src/devices/nm-device.c | 33 +++++++++++++++++++++++++++++- src/devices/nm-device.h | 3 +++ src/devices/wwan/nm-device-modem.c | 13 ++++++++++++ 5 files changed, 60 insertions(+), 1 deletion(-) diff --git a/libnm/nm-device.c b/libnm/nm-device.c index e80ac707d8..cd14c0e902 100644 --- a/libnm/nm-device.c +++ b/libnm/nm-device.c @@ -979,6 +979,9 @@ nm_device_get_type_description (NMDevice *device) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device); const char *desc, *typename; + /* BEWARE: this function should return the same value + * as nm_device_get_type_description() in nm-core. */ + g_return_val_if_fail (NM_IS_DEVICE (device), NULL); if (priv->type_description) diff --git a/src/devices/nm-device-generic.c b/src/devices/nm-device-generic.c index 8b328e07fe..5841d834ff 100644 --- a/src/devices/nm-device-generic.c +++ b/src/devices/nm-device-generic.c @@ -54,6 +54,14 @@ get_generic_capabilities (NMDevice *dev) return NM_DEVICE_CAP_NONE; } +static const char * +get_type_description (NMDevice *device) +{ + if (NM_DEVICE_GENERIC_GET_PRIVATE (device)->type_description) + return NM_DEVICE_GENERIC_GET_PRIVATE (device)->type_description; + return NM_DEVICE_CLASS (nm_device_generic_parent_class)->get_type_description (device); +} + static gboolean check_connection_compatible (NMDevice *device, NMConnection *connection) { @@ -184,6 +192,7 @@ nm_device_generic_class_init (NMDeviceGenericClass *klass) object_class->set_property = set_property; parent_class->get_generic_capabilities = get_generic_capabilities; + parent_class->get_type_description = get_type_description; parent_class->check_connection_compatible = check_connection_compatible; parent_class->update_connection = update_connection; diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index aab14708bc..d746a4c82b 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -189,6 +189,7 @@ typedef struct { int ip_ifindex; NMDeviceType type; char * type_desc; + char * type_description; NMDeviceCapabilities capabilities; char * driver; char * driver_version; @@ -818,6 +819,34 @@ nm_device_get_type_desc (NMDevice *self) return NM_DEVICE_GET_PRIVATE (self)->type_desc; } +const char * +nm_device_get_type_description (NMDevice *self) +{ + g_return_val_if_fail (self != NULL, NULL); + + /* Beware: this function should return the same + * value as nm_device_get_type_description() in libnm. */ + + return NM_DEVICE_GET_CLASS (self)->get_type_description (self); +} + +static const char * +get_type_description (NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + if (!priv->type_description) { + const char *typename; + + typename = G_OBJECT_TYPE_NAME (self); + if (g_str_has_prefix (typename, "NMDevice")) + typename += 8; + priv->type_description = g_ascii_strdown (typename, -1); + } + + return priv->type_description; +} + gboolean nm_device_has_carrier (NMDevice *self) { @@ -8638,6 +8667,7 @@ finalize (GObject *object) g_free (priv->driver_version); g_free (priv->firmware_version); g_free (priv->type_desc); + g_free (priv->type_description); g_free (priv->dhcp_anycast_address); g_hash_table_unref (priv->ip6_saved_properties); @@ -8655,7 +8685,7 @@ set_property (GObject *object, guint prop_id, NMPlatformLink *platform_device; const char *hw_addr, *p; guint count; - + switch (prop_id) { case PROP_PLATFORM_DEVICE: platform_device = g_value_get_pointer (value); @@ -8917,6 +8947,7 @@ nm_device_class_init (NMDeviceClass *klass) klass->act_stage4_ip6_config_timeout = act_stage4_ip6_config_timeout; klass->have_any_ready_slaves = have_any_ready_slaves; + klass->get_type_description = get_type_description; klass->spec_match_list = spec_match_list; klass->can_auto_connect = can_auto_connect; klass->check_connection_compatible = check_connection_compatible; diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index b44d2c2721..ef61dba72d 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -210,6 +210,8 @@ typedef struct { /* Sync deactivating (in the DISCONNECTED phase) */ void (* deactivate) (NMDevice *self); + const char *(*get_type_description) (NMDevice *self); + NMMatchSpecMatchType (* spec_match_list) (NMDevice *self, const GSList *specs); /* Update the connection with currently configured L2 settings */ @@ -276,6 +278,7 @@ int nm_device_get_ip_ifindex(NMDevice *dev); const char * nm_device_get_driver (NMDevice *dev); const char * nm_device_get_driver_version (NMDevice *dev); const char * nm_device_get_type_desc (NMDevice *dev); +const char * nm_device_get_type_description (NMDevice *dev); NMDeviceType nm_device_get_device_type (NMDevice *dev); int nm_device_get_priority (NMDevice *dev); diff --git a/src/devices/wwan/nm-device-modem.c b/src/devices/wwan/nm-device-modem.c index c02f5def9b..ca724c046c 100644 --- a/src/devices/wwan/nm-device-modem.c +++ b/src/devices/wwan/nm-device-modem.c @@ -372,6 +372,18 @@ get_generic_capabilities (NMDevice *device) return NM_DEVICE_CAP_IS_NON_KERNEL; } +static const char * +get_type_description (NMDevice *device) +{ + NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (device); + + if (NM_FLAGS_HAS (priv->current_caps, NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS)) + return "gsm"; + if (NM_FLAGS_HAS (priv->current_caps, NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO)) + return "cdma"; + return NM_DEVICE_CLASS (nm_device_modem_parent_class)->get_type_description (device); +} + static gboolean check_connection_compatible (NMDevice *device, NMConnection *connection) { @@ -741,6 +753,7 @@ nm_device_modem_class_init (NMDeviceModemClass *mclass) object_class->constructed = constructed; device_class->get_generic_capabilities = get_generic_capabilities; + device_class->get_type_description = get_type_description; device_class->check_connection_compatible = check_connection_compatible; device_class->check_connection_available = check_connection_available; device_class->complete_connection = complete_connection; From 1429ef7249ae106fa4f21b9b816c8ae10dae5532 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 15 May 2015 14:30:40 +0200 Subject: [PATCH 2/8] device: add device-spec "type:" Support a device-spec to match by device-type. This matches on the value as shown by nmcli -f GENERAL.TYPE device show (cherry picked from commit 3fb60edf9faf5f7dfd6a190202cab371a65233f4) --- man/NetworkManager.conf.xml.in | 5 +++++ src/NetworkManagerUtils.c | 38 ++++++++++++++++++++++++++++++++-- src/NetworkManagerUtils.h | 1 + src/devices/nm-device.c | 4 ++++ 4 files changed, 46 insertions(+), 2 deletions(-) diff --git a/man/NetworkManager.conf.xml.in b/man/NetworkManager.conf.xml.in index 79db1a2de2..b89efc7f60 100644 --- a/man/NetworkManager.conf.xml.in +++ b/man/NetworkManager.conf.xml.in @@ -606,6 +606,11 @@ unmanaged-devices=mac:00:22:68:1c:59:b1;mac:00:1E:65:30:D1:C4;interface-name:eth s390-subchannels:HWADDR Match the device based on the subchannel address. Globbing is not supported + + type:TYPE + Match the device type. Valid type names are as reported by "nmcli -f GENERAL.TYPE device show". + Globbing is not supported. + except:SPEC Negative match of a device. SPEC must be explicitly qualified with diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index 980b6a8d96..a989813d47 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -869,6 +869,7 @@ nm_utils_find_helper(const char *progname, const char *try_first, GError **error #define MAC_TAG "mac:" #define INTERFACE_NAME_TAG "interface-name:" +#define DEVICE_TYPE_TAG "type:" #define SUBCHAN_TAG "s390-subchannels:" #define EXCEPT_TAG "except:" @@ -883,6 +884,37 @@ _match_except (const char *spec_str, gboolean *out_except) return spec_str; } +NMMatchSpecMatchType +nm_match_spec_device_type (const GSList *specs, const char *device_type) +{ + const GSList *iter; + NMMatchSpecMatchType match = NM_MATCH_SPEC_NO_MATCH; + + if (!device_type || !*device_type) + return NM_MATCH_SPEC_NO_MATCH; + + for (iter = specs; iter; iter = g_slist_next (iter)) { + const char *spec_str = iter->data; + gboolean except; + + if (!spec_str || !*spec_str) + continue; + + spec_str = _match_except (spec_str, &except); + + if (g_ascii_strncasecmp (spec_str, DEVICE_TYPE_TAG, STRLEN (DEVICE_TYPE_TAG)) != 0) + continue; + + spec_str += STRLEN (DEVICE_TYPE_TAG); + if (strcmp (spec_str, device_type) == 0) { + if (except) + return NM_MATCH_SPEC_NEG_MATCH; + match = NM_MATCH_SPEC_MATCH; + } + } + return match; +} + NMMatchSpecMatchType nm_match_spec_hwaddr (const GSList *specs, const char *hwaddr) { @@ -901,7 +933,8 @@ nm_match_spec_hwaddr (const GSList *specs, const char *hwaddr) spec_str = _match_except (spec_str, &except); if ( !g_ascii_strncasecmp (spec_str, INTERFACE_NAME_TAG, STRLEN (INTERFACE_NAME_TAG)) - || !g_ascii_strncasecmp (spec_str, SUBCHAN_TAG, STRLEN (SUBCHAN_TAG))) + || !g_ascii_strncasecmp (spec_str, SUBCHAN_TAG, STRLEN (SUBCHAN_TAG)) + || !g_ascii_strncasecmp (spec_str, DEVICE_TYPE_TAG, STRLEN (DEVICE_TYPE_TAG))) continue; if (!g_ascii_strncasecmp (spec_str, MAC_TAG, STRLEN (MAC_TAG))) @@ -937,7 +970,8 @@ nm_match_spec_interface_name (const GSList *specs, const char *interface_name) spec_str = _match_except (spec_str, &except); if ( !g_ascii_strncasecmp (spec_str, MAC_TAG, STRLEN (MAC_TAG)) - || !g_ascii_strncasecmp (spec_str, SUBCHAN_TAG, STRLEN (SUBCHAN_TAG))) + || !g_ascii_strncasecmp (spec_str, SUBCHAN_TAG, STRLEN (SUBCHAN_TAG)) + || !g_ascii_strncasecmp (spec_str, DEVICE_TYPE_TAG, STRLEN (DEVICE_TYPE_TAG))) continue; if (!g_ascii_strncasecmp (spec_str, INTERFACE_NAME_TAG, STRLEN (INTERFACE_NAME_TAG))) { diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h index 3bd7252876..03836abd5d 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -102,6 +102,7 @@ typedef enum { NM_MATCH_SPEC_NEG_MATCH = 2, } NMMatchSpecMatchType; +NMMatchSpecMatchType nm_match_spec_device_type (const GSList *specs, const char *device_type); NMMatchSpecMatchType nm_match_spec_hwaddr (const GSList *specs, const char *hwaddr); NMMatchSpecMatchType nm_match_spec_s390_subchannels (const GSList *specs, const char *subchannels); NMMatchSpecMatchType nm_match_spec_interface_name (const GSList *specs, const char *interface_name); diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index d746a4c82b..2432ea4fb0 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -8383,6 +8383,10 @@ spec_match_list (NMDevice *self, const GSList *specs) m = nm_match_spec_interface_name (specs, nm_device_get_iface (self)); matched = MAX (matched, m); } + if (matched != NM_MATCH_SPEC_NEG_MATCH) { + m = nm_match_spec_device_type (specs, nm_device_get_type_description (self)); + matched = MAX (matched, m); + } return matched; } From a76deff2f6055034fd1e770b7e7d6b23f39f1a7d Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 15 May 2015 17:00:31 +0200 Subject: [PATCH 3/8] config: publish nm_config_keyfile_get_boolean() utility function (cherry picked from commit f031b926c452aea5a28390eee2cfb9b9f0d15652) --- src/nm-config.c | 16 ++++++++-------- src/nm-config.h | 4 ++++ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/nm-config.c b/src/nm-config.c index 25e4902bde..c7e61b559e 100644 --- a/src/nm-config.c +++ b/src/nm-config.c @@ -107,11 +107,11 @@ static void _set_config_data (NMConfig *self, NMConfigData *new_data); /************************************************************************/ -static gboolean -_get_bool_value (GKeyFile *keyfile, - const char *section, - const char *key, - gboolean default_value) +gboolean +nm_config_keyfile_get_boolean (GKeyFile *keyfile, + const char *section, + const char *key, + gboolean default_value) { gboolean value = default_value; char *str; @@ -828,9 +828,9 @@ init_sync (GInitable *initable, GCancellable *cancellable, GError **error) if (!priv->plugins) priv->plugins = g_new0 (char *, 1); - priv->monitor_connection_files = _get_bool_value (keyfile, "main", "monitor-connection-files", FALSE); + priv->monitor_connection_files = nm_config_keyfile_get_boolean (keyfile, "main", "monitor-connection-files", FALSE); - priv->auth_polkit = _get_bool_value (keyfile, "main", "auth-polkit", NM_CONFIG_DEFAULT_AUTH_POLKIT); + priv->auth_polkit = nm_config_keyfile_get_boolean (keyfile, "main", "auth-polkit", NM_CONFIG_DEFAULT_AUTH_POLKIT); priv->dhcp_client = g_key_file_get_value (keyfile, "main", "dhcp", NULL); @@ -839,7 +839,7 @@ init_sync (GInitable *initable, GCancellable *cancellable, GError **error) priv->debug = g_key_file_get_value (keyfile, "main", "debug", NULL); - priv->configure_and_quit = _get_bool_value (keyfile, "main", "configure-and-quit", FALSE); + priv->configure_and_quit = nm_config_keyfile_get_boolean (keyfile, "main", "configure-and-quit", FALSE); no_auto_default_orig_list = nm_config_get_device_match_spec (keyfile, "main", "no-auto-default"); diff --git a/src/nm-config.h b/src/nm-config.h index e72132af9d..29d6566323 100644 --- a/src/nm-config.h +++ b/src/nm-config.h @@ -89,6 +89,10 @@ NMConfig *nm_config_setup (const NMConfigCmdLineOptions *cli, GError **error); void nm_config_reload (NMConfig *config); GKeyFile *nm_config_create_keyfile (void); +gboolean nm_config_keyfile_get_boolean (GKeyFile *keyfile, + const char *section, + const char *key, + gboolean default_value); GSList *nm_config_get_device_match_spec (const GKeyFile *keyfile, const char *group, const char *key); G_END_DECLS From a64e81703e3cb03b26ee62555f08c7c8a0e77972 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 15 May 2015 11:36:28 +0200 Subject: [PATCH 4/8] config: support a [connection] section to NetworkManager.conf to specify connection defaults Add support for a new section [connection] in NetworkManager.conf. If the connection leaves an option at "unknown"/"default", we can support overwriting the value from global configuration. We also support other sections that are named with "connection" as a prefix, such as [connection2], [connection-wifi]. This is to support multiple default values that can be applied depending on the used device. I think this has great potential. Only downside is that when the user looks at a connection value, it will see that it is unspecified. But the actually used value depends on the device type and might not be obvious. https://bugzilla.gnome.org/show_bug.cgi?id=695383 https://bugzilla.redhat.com/show_bug.cgi?id=1164677 (cherry picked from commit dc0193ac023e30a9a3794e78c66f8c5266695a60) --- man/NetworkManager.conf.xml.in | 71 ++++++++++++++++ src/nm-config-data.c | 122 +++++++++++++++++++++++++++ src/nm-config-data.h | 4 + src/tests/config/NetworkManager.conf | 24 ++++++ src/tests/config/test-config.c | 51 +++++++++++ 5 files changed, 272 insertions(+) diff --git a/man/NetworkManager.conf.xml.in b/man/NetworkManager.conf.xml.in index b89efc7f60..6e60fc915f 100644 --- a/man/NetworkManager.conf.xml.in +++ b/man/NetworkManager.conf.xml.in @@ -439,6 +439,77 @@ unmanaged-devices=mac:00:22:68:1c:59:b1;mac:00:1E:65:30:D1:C4;interface-name:eth + + <literal>connection</literal> section + This section allows to specify default values for + connections. Not all properties can be overwritten, only a selected + list below. You can have multiple connection + sections, by having different sections with a name that all start + with "connection". + + Example: + +[connection] +ipv6.ip6-privacy=0 + +[connection-wifi-wlan0] +match-device=interface-name:wlan0 +ipv4.route-metric=50 + +[connection-wifi-other] +match-device=type:wifi +ipv4.route-metric=55 +ipv6.ip6-privacy=1 + + + + + The sections are considered in order of appearance, with the + exception that the [connection] section is always + considered last. In the example above, this order is [connection-wifi-wlan0], + [connection-wlan-other], and [connection]. + When checking for a default configuration value, the section are searched until + the requested value is found. + In the example above, "ipv4.route-metric" for wlan0 interface is set to 50, + and for all other Wi-Fi typed interfaces to 55. Also, Wi-Fi devices would have + IPv6 private addresses enabled by default, but other devices would have it disabled. + Note that also "wlan0" gets "ipv6.ip6-privacy=1", because although the section + "[connection-wifi-wlan0]" matches the device, it does not contain that property + and the search continues. + This is just an example, currently these properties are not overwritable. + + + + + + match-device + An optional device spec that restricts + when the section applies. See + for the possible values. + + + + stop-match + An optional boolean value which defaults to + no. If the section matches (based on + match-device), further sections will not be + considered even if the property in question is not present. In + the example above, if [connection-wifi-wlan0] would + have stop-match set to yes, + its ipv6.ip6-privacy value would be + unspecified. + + + + + + + The following properties are supported to have their default values configured: + + + + + <literal>connectivity</literal> section This section controls NetworkManager's optional connectivity diff --git a/src/nm-config-data.c b/src/nm-config-data.c index 2569f7ca30..e53d8fbb11 100644 --- a/src/nm-config-data.c +++ b/src/nm-config-data.c @@ -27,6 +27,19 @@ #include "nm-device.h" #include "gsystem-local-alloc.h" #include "nm-core-internal.h" +#include "nm-utils-internal.h" + +typedef struct { + char *group_name; + gboolean stop_match; + struct { + /* have a separate boolean field @has, because a @spec with + * value %NULL does not necessarily mean, that the property + * "match-device" was unspecified. */ + gboolean has; + GSList *spec; + } match_device; +} ConnectionInfo; typedef struct { char *config_main_file; @@ -34,6 +47,10 @@ typedef struct { GKeyFile *keyfile; + /* A zero-terminated list of pre-processed information from the + * [connection] sections. This is to speed up lookup. */ + ConnectionInfo *connection_infos; + struct { char *uri; char *response; @@ -163,6 +180,100 @@ nm_config_data_get_assume_ipv6ll_only (const NMConfigData *self, NMDevice *devic /************************************************************************/ +char * +nm_config_data_get_connection_default (const NMConfigData *self, + const char *property, + NMDevice *device) +{ + NMConfigDataPrivate *priv; + const ConnectionInfo *connection_info; + + g_return_val_if_fail (self, NULL); + g_return_val_if_fail (property && *property, NULL); + g_return_val_if_fail (strchr (property, '.'), NULL); + + priv = NM_CONFIG_DATA_GET_PRIVATE (self); + + if (!priv->connection_infos) + return NULL; + + for (connection_info = &priv->connection_infos[0]; connection_info->group_name; connection_info++) { + char *value; + gboolean match; + + value = g_key_file_get_value (priv->keyfile, connection_info->group_name, property, NULL); + if (!value && !connection_info->stop_match) + continue; + + match = TRUE; + if (connection_info->match_device.has) + match = device && nm_device_spec_match_list (device, connection_info->match_device.spec); + + if (match) + return value; + g_free (value); + } + return NULL; +} + +static ConnectionInfo * +_get_connection_infos (GKeyFile *keyfile) +{ + char **groups; + guint i; + char *connection_tag = NULL; + GSList *connection_groups = NULL; + ConnectionInfo *connection_infos = NULL; + + /* get the list of existing [connection.\+] sections that we consider + * for nm_config_data_get_connection_default(). Also, get them + * in the right order. */ + groups = g_key_file_get_groups (keyfile, NULL); + for (i = 0; groups && groups[i]; i++) { + if (g_str_has_prefix (groups[i], "connection")) { + if (strlen (groups[i]) == STRLEN ("connection")) + connection_tag = groups[i]; + else + connection_groups = g_slist_prepend (connection_groups, groups[i]); + } else + g_free (groups[i]); + } + g_free (groups); + if (connection_tag) { + /* We want the group "connection" checked at last, so that + * all other "connection.\+" have preference. Those other + * groups are checked in order of appearance. */ + connection_groups = g_slist_prepend (connection_groups, connection_tag); + } + if (connection_groups) { + guint len = g_slist_length (connection_groups); + GSList *iter; + + connection_infos = g_new0 (ConnectionInfo, len + 1); + for (iter = connection_groups; iter; iter = iter->next) { + ConnectionInfo *connection_info; + char *value; + + nm_assert (len >= 1); + connection_info = &connection_infos[--len]; + connection_info->group_name = iter->data; + + value = g_key_file_get_value (keyfile, iter->data, "match-device", NULL); + if (value) { + connection_info->match_device.has = TRUE; + connection_info->match_device.spec = nm_match_spec_split (value); + g_free (value); + } + connection_info->stop_match = nm_config_keyfile_get_boolean (keyfile, iter->data, "stop-match", FALSE); + } + g_slist_free (connection_groups); + } + + return connection_infos; +} + +/************************************************************************/ + static gboolean _keyfile_a_contains_all_in_b (GKeyFile *kf_a, GKeyFile *kf_b) { @@ -312,6 +423,7 @@ static void finalize (GObject *gobject) { NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE (gobject); + guint i; g_free (priv->config_main_file); g_free (priv->config_description); @@ -327,6 +439,14 @@ finalize (GObject *gobject) g_slist_free_full (priv->ignore_carrier, g_free); g_slist_free_full (priv->assume_ipv6ll_only, g_free); + if (priv->connection_infos) { + for (i = 0; priv->connection_infos[i].group_name; i++) { + g_free (priv->connection_infos[i].group_name); + g_slist_free_full (priv->connection_infos[i].match_device.spec, g_free); + } + g_free (priv->connection_infos); + } + g_key_file_unref (priv->keyfile); G_OBJECT_CLASS (nm_config_data_parent_class)->finalize (gobject); @@ -344,6 +464,8 @@ constructed (GObject *object) NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE (self); char *interval; + priv->connection_infos = _get_connection_infos (priv->keyfile); + priv->connectivity.uri = g_key_file_get_value (priv->keyfile, "connectivity", "uri", NULL); priv->connectivity.response = g_key_file_get_value (priv->keyfile, "connectivity", "response", NULL); diff --git a/src/nm-config-data.h b/src/nm-config-data.h index 0c3e3d1455..07140f82b6 100644 --- a/src/nm-config-data.h +++ b/src/nm-config-data.h @@ -92,6 +92,10 @@ const char *nm_config_data_get_dns_mode (const NMConfigData *self); gboolean nm_config_data_get_ignore_carrier (const NMConfigData *self, NMDevice *device); gboolean nm_config_data_get_assume_ipv6ll_only (const NMConfigData *self, NMDevice *device); +char *nm_config_data_get_connection_default (const NMConfigData *self, + const char *property, + NMDevice *device); + G_END_DECLS #endif /* NM_CONFIG_DATA_H */ diff --git a/src/tests/config/NetworkManager.conf b/src/tests/config/NetworkManager.conf index 401ba48a72..36113661f2 100644 --- a/src/tests/config/NetworkManager.conf +++ b/src/tests/config/NetworkManager.conf @@ -13,3 +13,27 @@ response=Hello [extra-section] extra-key=some value + + + +[connection] +ipv4.route-metric=50 +ipv6.ip6_privacy=0 +dummy.test1=no +dummy.test2=no + +[connection.dev51] +match-device=mac:00:00:00:00:00:51 +stop-match=yes +ipv4.route-metric=51 +dummy.test1=yes + +[connection.dev52] +match-device=mac:00:00:00:00:00:52 +ipv4.route-metric=52 + +[connection.public] +match-device=interface-name:wlan1 +# match-wifi is not yet implemented. Just an idea what could be useful. +match-wifi=ssid:*[Ss]tarbucks*|*University* +ipv6.ip6_privacy=2 diff --git a/src/tests/config/test-config.c b/src/tests/config/test-config.c index 67ba5904ec..7ce3c1ee7c 100644 --- a/src/tests/config/test-config.c +++ b/src/tests/config/test-config.c @@ -94,6 +94,9 @@ test_config_simple (void) GError *error = NULL; const char **plugins; char *value; + gs_unref_object NMDevice *dev50 = nm_test_device_new ("00:00:00:00:00:50"); + gs_unref_object NMDevice *dev51 = nm_test_device_new ("00:00:00:00:00:51"); + gs_unref_object NMDevice *dev52 = nm_test_device_new ("00:00:00:00:00:52"); config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "/no/such/dir", NULL); @@ -122,6 +125,54 @@ test_config_simple (void) g_assert_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND); g_clear_error (&error); + value = nm_config_data_get_value (nm_config_get_data_orig (config), "connection", "ipv6.ip6_privacy", NULL); + g_assert_cmpstr (value, ==, "0"); + g_free (value); + + value = nm_config_data_get_value (nm_config_get_data_orig (config), "connection.dev51", "ipv4.route-metric", NULL); + g_assert_cmpstr (value, ==, "51"); + g_free (value); + + + value = nm_config_data_get_connection_default (nm_config_get_data_orig (config), "ipv6.route-metric", NULL); + g_assert_cmpstr (value, ==, NULL); + g_free (value); + + + value = nm_config_data_get_connection_default (nm_config_get_data_orig (config), "ipv4.route-metric", NULL); + g_assert_cmpstr (value, ==, "50"); + g_free (value); + + value = nm_config_data_get_connection_default (nm_config_get_data_orig (config), "ipv4.route-metric", dev50); + g_assert_cmpstr (value, ==, "50"); + g_free (value); + + value = nm_config_data_get_connection_default (nm_config_get_data_orig (config), "ipv4.route-metric", dev51); + g_assert_cmpstr (value, ==, "51"); + g_free (value); + + value = nm_config_data_get_connection_default (nm_config_get_data_orig (config), "ipv4.route-metric", dev52); + g_assert_cmpstr (value, ==, "52"); + g_free (value); + + + value = nm_config_data_get_connection_default (nm_config_get_data_orig (config), "dummy.test1", dev51); + g_assert_cmpstr (value, ==, "yes"); + g_free (value); + + value = nm_config_data_get_connection_default (nm_config_get_data_orig (config), "dummy.test1", dev50); + g_assert_cmpstr (value, ==, "no"); + g_free (value); + + value = nm_config_data_get_connection_default (nm_config_get_data_orig (config), "dummy.test2", dev51); + g_assert_cmpstr (value, ==, NULL); + g_free (value); + + value = nm_config_data_get_connection_default (nm_config_get_data_orig (config), "dummy.test2", dev50); + g_assert_cmpstr (value, ==, "no"); + g_free (value); + + g_object_unref (config); } From 923aa9d7275b245e828b499aeb66d5cbf810bc24 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 15 May 2015 12:21:59 +0200 Subject: [PATCH 5/8] device: make route-metric configurable per-device The route-metric can be configured per connection via the ipv4.route-metric and ipv6.route-metric fields. When the value is left at -1 (the default), we would determine the route-metric based on the device type (nm_device_get_priority()). Extend that scheme by making the default value overwritable in NetworkManager.conf. (cherry picked from commit 59a991725af95e15b9e557008664906d82549d95) --- man/NetworkManager.conf.xml.in | 8 +++- src/devices/nm-device.c | 75 ++++++++++++++++++++-------------- 2 files changed, 51 insertions(+), 32 deletions(-) diff --git a/man/NetworkManager.conf.xml.in b/man/NetworkManager.conf.xml.in index 6e60fc915f..7b651132d8 100644 --- a/man/NetworkManager.conf.xml.in +++ b/man/NetworkManager.conf.xml.in @@ -476,7 +476,7 @@ ipv6.ip6-privacy=1 Note that also "wlan0" gets "ipv6.ip6-privacy=1", because although the section "[connection-wifi-wlan0]" matches the device, it does not contain that property and the search continues. - This is just an example, currently these properties are not overwritable. + This is just an example, ipv6.ip6-privacy property is currently not overwritable. @@ -506,6 +506,12 @@ ipv6.ip6-privacy=1 The following properties are supported to have their default values configured: + + ipv4.route-metric + + + ipv6.route-metric + diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 2432ea4fb0..e7be3f1288 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -735,50 +735,63 @@ nm_device_get_priority (NMDevice *self) return 11000; } -guint32 -nm_device_get_ip4_route_metric (NMDevice *self) +static guint32 +_get_ipx_route_metric (NMDevice *self, + gboolean is_v4) { + char *value; + gint64 route_metric; + NMSettingIPConfig *s_ip; NMConnection *connection; - NMSettingIPConfig *s_ip = NULL; - gint64 route_metric = -1; g_return_val_if_fail (NM_IS_DEVICE (self), G_MAXUINT32); connection = nm_device_get_connection (self); - if (connection) - s_ip = nm_connection_get_setting_ip4_config (connection); + if (connection) { + s_ip = is_v4 + ? nm_connection_get_setting_ip4_config (connection) + : nm_connection_get_setting_ip6_config (connection); - /* Slave interfaces don't have IP settings, but we may get here when - * external changes are made or when noticing IP changes when starting - * the slave connection. - */ - if (s_ip) - route_metric = nm_setting_ip_config_get_route_metric (s_ip); + /* Slave interfaces don't have IP settings, but we may get here when + * external changes are made or when noticing IP changes when starting + * the slave connection. + */ + if (s_ip) { + route_metric = nm_setting_ip_config_get_route_metric (s_ip); + if (route_metric >= 0) + goto out; + } + } - return route_metric >= 0 ? route_metric : nm_device_get_priority (self); + /* use the current NMConfigData, which makes this configuration reloadable. + * Note that that means that the route-metric might change between SIGHUP. + * You must cache the returned value if that is a problem. */ + value = nm_config_data_get_connection_default (nm_config_get_data (nm_config_get ()), + is_v4 ? "ipv4.route-metric" : "ipv6.route-metric", self); + if (value) { + route_metric = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXUINT32, -1); + g_free (value); + + if (route_metric >= 0) + goto out; + } + route_metric = nm_device_get_priority (self); +out: + if (!is_v4) + route_metric = nm_utils_ip6_route_metric_normalize (route_metric); + return route_metric; +} + +guint32 +nm_device_get_ip4_route_metric (NMDevice *self) +{ + return _get_ipx_route_metric (self, TRUE); } guint32 nm_device_get_ip6_route_metric (NMDevice *self) { - NMConnection *connection; - NMSettingIPConfig *s_ip = NULL; - gint64 route_metric = -1; - - g_return_val_if_fail (NM_IS_DEVICE (self), G_MAXUINT32); - - connection = nm_device_get_connection (self); - if (connection) - s_ip = nm_connection_get_setting_ip6_config (connection); - - /* Slave interfaces don't have IP settings, but we may get here when - * external changes are made or when noticing IP changes when starting - * the slave connection. - */ - if (s_ip) - route_metric = nm_setting_ip_config_get_route_metric (s_ip); - - return route_metric >= 0 ? route_metric : nm_device_get_priority (self); + return _get_ipx_route_metric (self, FALSE); } const NMPlatformIP4Route * From 905cf30b51917e37ea074e5f3d83436a107d01c5 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 16 Apr 2015 16:35:32 +0200 Subject: [PATCH 6/8] libnm/doc: document behavior of setting ip6-privacy in /etc/sysctl.conf https://bugzilla.gnome.org/show_bug.cgi?id=721200 (cherry picked from commit e4293788fcfd8f0026fed2c90aa6e1b02a3036d7) --- libnm-core/nm-setting-ip6-config.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libnm-core/nm-setting-ip6-config.c b/libnm-core/nm-setting-ip6-config.c index 29ca551525..fa9eb1500e 100644 --- a/libnm-core/nm-setting-ip6-config.c +++ b/libnm-core/nm-setting-ip6-config.c @@ -504,9 +504,13 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *ip6_class) * enabled, it makes the kernel generate a temporary IPv6 address in * addition to the public one generated from MAC address via modified * EUI-64. This enhances privacy, but could cause problems in some - * applications, on the other hand. The permitted values are: 0: disabled, - * 1: enabled (prefer public address), 2: enabled (prefer temporary + * applications, on the other hand. The permitted values are: -1: unknown, + * 0: disabled, 1: enabled (prefer public address), 2: enabled (prefer temporary * addresses). + * + * This per-connection value is ignored when setting + * "net.ipv6.conf.default.use_tempaddr" in /etc/sysctl.conf or + * /lib/sysctl.d/sysctl.conf to either "0", "1", or "2". **/ /* ---ifcfg-rh--- * property: ip6-privacy From a6630e4fad826cb79886476915d392edf554e783 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 16 Apr 2015 16:38:00 +0200 Subject: [PATCH 7/8] device: add global configuration default for ip6-privacy (use_tempaddr, RFC4941) Support default value for setting 'ipv6.ip6-privacy' in NetworkManager.conf. If the global value is unset, preserve old behavior of looking into /etc/sycctl.conf first. That behavior was introduced with commit d376270bfe673c041e610a981bd6c77c7cb37ba1, since we support ip6-privacy setting. If the global value is set to "unknown", add a new fallback that instead reads the runtime value from "/proc/sys/net/ipv6/conf/default/use_tempaddr" This seems more sensible behavior because we fallback to sysctl, but instead of looking at static files in /etc, read /proc. But to preserve the old behavior, we only do that when a global value is configured at all. https://bugzilla.gnome.org/show_bug.cgi?id=721200 (cherry picked from commit e729dd70ae00a23968c621ab2da7666db8b2c20a) --- libnm-core/nm-setting-ip6-config.c | 17 +++++- man/NetworkManager.conf.xml.in | 10 +++- src/devices/nm-device.c | 89 +++++++++++++++++++++++++----- 3 files changed, 97 insertions(+), 19 deletions(-) diff --git a/libnm-core/nm-setting-ip6-config.c b/libnm-core/nm-setting-ip6-config.c index fa9eb1500e..1bb40f0ed5 100644 --- a/libnm-core/nm-setting-ip6-config.c +++ b/libnm-core/nm-setting-ip6-config.c @@ -508,9 +508,20 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *ip6_class) * 0: disabled, 1: enabled (prefer public address), 2: enabled (prefer temporary * addresses). * - * This per-connection value is ignored when setting - * "net.ipv6.conf.default.use_tempaddr" in /etc/sysctl.conf or - * /lib/sysctl.d/sysctl.conf to either "0", "1", or "2". + * This property can be configured with a default value in global configuration + * NetworkManager.conf. + * + * If the global configuration value "connection.ipv6.ip6-privacy" + * is not specified, the sysctl value "net.ipv6.conf.default.use_tempaddr" in /etc/sysctl.conf or + * /lib/sysctl.d/sysctl.conf is always checked first. If set to "0", "1", or "2", that + * value is always used and any per-connection setting is ignored. This behavior is kept for + * backward compatiblity. + * + * Otherwise this per-connection setting is honored next. Having a per-connection setting set + * to "-1" (unknown) means fallback to global configuration "ipv6.ip6-privacy". + * + * If the global configuration is explicitly set to "-1", fallback to read + * "/proc/sys/net/ipv6/conf/default/use_tempaddr". **/ /* ---ifcfg-rh--- * property: ip6-privacy diff --git a/man/NetworkManager.conf.xml.in b/man/NetworkManager.conf.xml.in index 7b651132d8..57635b81a2 100644 --- a/man/NetworkManager.conf.xml.in +++ b/man/NetworkManager.conf.xml.in @@ -476,7 +476,6 @@ ipv6.ip6-privacy=1 Note that also "wlan0" gets "ipv6.ip6-privacy=1", because although the section "[connection-wifi-wlan0]" matches the device, it does not contain that property and the search continues. - This is just an example, ipv6.ip6-privacy property is currently not overwritable. @@ -509,6 +508,15 @@ ipv6.ip6-privacy=1 ipv4.route-metric + + ipv6.ip6-privacy + If this value is unset, NetworkManager will always first check "/etc/sysctl.conf" and "/etc/sysctl.d/sysctl.conf" whether + they contain "net.ipv6.conf.default.use_tempaddr". This value is then preferred over any per-connection + setting. That step is omitted when setting the global configuration value ipv6.ip6-privacy + to any value. If ipv6.ip6-privacy is set but neither "0", "1", or "2", use the content of + "/proc/sys/net/ipv6/conf/default/use_tempaddr" as last fallback. + + ipv6.route-metric diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index e7be3f1288..5c057ab74d 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -4597,8 +4597,10 @@ set_nm_ipv6ll (NMDevice *self, gboolean enable) } } +/************************************************************************/ + static NMSettingIP6ConfigPrivacy -use_tempaddr_clamp (NMSettingIP6ConfigPrivacy use_tempaddr) +_ip6_privacy_clamp (NMSettingIP6ConfigPrivacy use_tempaddr) { switch (use_tempaddr) { case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED: @@ -4614,7 +4616,7 @@ use_tempaddr_clamp (NMSettingIP6ConfigPrivacy use_tempaddr) * /lib/sysctl.d/sysctl.conf */ static NMSettingIP6ConfigPrivacy -ip6_use_tempaddr (void) +_ip6_privacy_sysctl (void) { char *contents = NULL; const char *group_name = "[forged_group]\n"; @@ -4638,7 +4640,7 @@ ip6_use_tempaddr (void) tmp = g_key_file_get_integer (keyfile, "forged_group", "net.ipv6.conf.default.use_tempaddr", &error); if (error == NULL) - ret = use_tempaddr_clamp (tmp); + ret = _ip6_privacy_clamp (tmp); done: g_free (contents); @@ -4649,6 +4651,74 @@ done: return ret; } +static NMSettingIP6ConfigPrivacy +_ip6_privacy_get (NMDevice *self) +{ + NMSettingIP6ConfigPrivacy ip6_privacy; + gs_free char *value = NULL; + NMConnection *connection; + + g_return_val_if_fail (self, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); + + value = nm_config_data_get_connection_default (nm_config_get_data (nm_config_get ()), + "ipv6.ip6-privacy", self); + + /* 1.) If (and only if) the default value is not configured, check _ip6_privacy_sysctl() + * first. This is to preserve backward compatibility. In this case -- having no + * default value in global configuration, but use_tempaddr configured in /etc/sysctl -- + * the per-connection setting is always ignored. */ + if (!value) { + ip6_privacy = _ip6_privacy_sysctl (); + if (ip6_privacy != NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN) + return ip6_privacy; + } + + /* 2.) Next we always look at the per-connection setting. If it is not -1 (unknown), + * use it. */ + connection = nm_device_get_connection (self); + if (connection) { + NMSettingIPConfig *s_ip6 = nm_connection_get_setting_ip6_config (connection); + + if (s_ip6) { + ip6_privacy = nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6)); + ip6_privacy = _ip6_privacy_clamp (ip6_privacy); + if (ip6_privacy != NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN) + return ip6_privacy; + } + } + + /* 3.) All options (per-connection, global, sysctl) are unset/default. + * Return UNKNOWN. Skip step 5.) because that would be a change in behavior + * compared to older versions. */ + if (!value) + return NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; + + /* 4.) use the default value from the configuration. */ + ip6_privacy = _nm_utils_ascii_str_to_int64 (value, 10, + NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN, + NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, + NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); + if (ip6_privacy != NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN) + return ip6_privacy; + + /* 5.) A default-value is configured, but it is invalid/unknown. Fallback to sysctl reading. + * + * _ip6_privacy_sysctl() only reads two files from /etc and does not support the complexity + * of parsing all files. Also, it only considers "net.ipv6.conf.default.use_tempaddr", + * not the per-interface values. This is kinda unexpected, but we do it in 1.) to preserve + * old behavior. + * + * Now, the user actively configured a default value to "unknown" and we can introduce new + * behavior without changing old behavior (step 1.). + * Instead of reading static config files in /etc, just read the current sysctl value. + * This works as NM only writes to "/proc/sys/net/ipv6/conf/IFNAME/use_tempaddr", but leaves + * the "default" entry untouched. */ + ip6_privacy = nm_platform_sysctl_get_int32 (NM_PLATFORM_GET, "/proc/sys/net/ipv6/conf/default/use_tempaddr", NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); + return _ip6_privacy_clamp (ip6_privacy); +} + +/****************************************************************/ + static gboolean ip6_requires_slaves (NMConnection *connection) { @@ -4747,18 +4817,7 @@ act_stage3_ip6_config_start (NMDevice *self, /* Re-enable IPv6 on the interface */ set_disable_ipv6 (self, "0"); - /* Enable/disable IPv6 Privacy Extensions. - * If a global value is configured by sysadmin (e.g. /etc/sysctl.conf), - * use that value instead of per-connection value. - */ - ip6_privacy = ip6_use_tempaddr (); - if (ip6_privacy == NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN) { - NMSettingIPConfig *s_ip6 = nm_connection_get_setting_ip6_config (connection); - - if (s_ip6) - ip6_privacy = nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6)); - } - ip6_privacy = use_tempaddr_clamp (ip6_privacy); + ip6_privacy = _ip6_privacy_get (self); if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0) { if (!addrconf6_start (self, ip6_privacy)) { From 1468f4edd2b57e5a76c11df2e397d050b0613d82 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 2 Jun 2015 17:38:07 +0200 Subject: [PATCH 8/8] device: remove reading ipv6 privacy setting from sysctl Since introduction for support of ip6-privacy (use_tempaddr, RFC4941) with commit d376270bfe673c041e610a981bd6c77c7cb37ba1, the sysctl value from /etc was always read first. This is problematic, because an explicit setting in the connection should not be ignored over a global configuration. Drop that old behavior. It was also problematic, because we did not read any files under /etc/sysctl.d (except for sysctl.conf). Also, we did not honor per-interface configurations. Now we also use as last fallback the value from /proc/sys/net/ipv6/conf/default/use_tempaddr That has the advantage of falling back to the system default value so that NM doesn't need to have it's own default policy (Related: https://bugzilla.redhat.com/show_bug.cgi?id=1187525). This is a change in behavior. (cherry picked from commit f3c61f814199b0dda5de7627e02583c87173841e) --- libnm-core/nm-setting-ip6-config.c | 15 ++----- man/NetworkManager.conf.xml.in | 5 +-- src/devices/nm-device.c | 72 +++--------------------------- 3 files changed, 9 insertions(+), 83 deletions(-) diff --git a/libnm-core/nm-setting-ip6-config.c b/libnm-core/nm-setting-ip6-config.c index 1bb40f0ed5..7e3ae4d4da 100644 --- a/libnm-core/nm-setting-ip6-config.c +++ b/libnm-core/nm-setting-ip6-config.c @@ -508,19 +508,10 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *ip6_class) * 0: disabled, 1: enabled (prefer public address), 2: enabled (prefer temporary * addresses). * - * This property can be configured with a default value in global configuration - * NetworkManager.conf. + * Having a per-connection setting set to "-1" (unknown) means fallback to + * global configuration "ipv6.ip6-privacy". * - * If the global configuration value "connection.ipv6.ip6-privacy" - * is not specified, the sysctl value "net.ipv6.conf.default.use_tempaddr" in /etc/sysctl.conf or - * /lib/sysctl.d/sysctl.conf is always checked first. If set to "0", "1", or "2", that - * value is always used and any per-connection setting is ignored. This behavior is kept for - * backward compatiblity. - * - * Otherwise this per-connection setting is honored next. Having a per-connection setting set - * to "-1" (unknown) means fallback to global configuration "ipv6.ip6-privacy". - * - * If the global configuration is explicitly set to "-1", fallback to read + * If also global configuration is unspecified or set to "-1", fallback to read * "/proc/sys/net/ipv6/conf/default/use_tempaddr". **/ /* ---ifcfg-rh--- diff --git a/man/NetworkManager.conf.xml.in b/man/NetworkManager.conf.xml.in index 57635b81a2..fac4616ff6 100644 --- a/man/NetworkManager.conf.xml.in +++ b/man/NetworkManager.conf.xml.in @@ -510,10 +510,7 @@ ipv6.ip6-privacy=1 ipv6.ip6-privacy - If this value is unset, NetworkManager will always first check "/etc/sysctl.conf" and "/etc/sysctl.d/sysctl.conf" whether - they contain "net.ipv6.conf.default.use_tempaddr". This value is then preferred over any per-connection - setting. That step is omitted when setting the global configuration value ipv6.ip6-privacy - to any value. If ipv6.ip6-privacy is set but neither "0", "1", or "2", use the content of + If ipv6.ip6-privacy is unset, use the content of "/proc/sys/net/ipv6/conf/default/use_tempaddr" as last fallback. diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 5c057ab74d..3d5cda21b9 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -4612,45 +4612,6 @@ _ip6_privacy_clamp (NMSettingIP6ConfigPrivacy use_tempaddr) } } -/* Get net.ipv6.conf.default.use_tempaddr value from /etc/sysctl.conf or - * /lib/sysctl.d/sysctl.conf - */ -static NMSettingIP6ConfigPrivacy -_ip6_privacy_sysctl (void) -{ - char *contents = NULL; - const char *group_name = "[forged_group]\n"; - char *sysctl_data = NULL; - GKeyFile *keyfile; - GError *error = NULL; - gint tmp; - NMSettingIP6ConfigPrivacy ret = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; - - /* Read file contents to a string. */ - if (!g_file_get_contents ("/etc/sysctl.conf", &contents, NULL, NULL)) - if (!g_file_get_contents ("/lib/sysctl.d/sysctl.conf", &contents, NULL, NULL)) - return NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; - - /* Prepend a group so that we can use GKeyFile parser. */ - sysctl_data = g_strdup_printf ("%s%s", group_name, contents); - - keyfile = g_key_file_new (); - if (!g_key_file_load_from_data (keyfile, sysctl_data, -1, G_KEY_FILE_NONE, NULL)) - goto done; - - tmp = g_key_file_get_integer (keyfile, "forged_group", "net.ipv6.conf.default.use_tempaddr", &error); - if (error == NULL) - ret = _ip6_privacy_clamp (tmp); - -done: - g_free (contents); - g_free (sysctl_data); - g_clear_error (&error); - g_key_file_free (keyfile); - - return ret; -} - static NMSettingIP6ConfigPrivacy _ip6_privacy_get (NMDevice *self) { @@ -4660,20 +4621,7 @@ _ip6_privacy_get (NMDevice *self) g_return_val_if_fail (self, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); - value = nm_config_data_get_connection_default (nm_config_get_data (nm_config_get ()), - "ipv6.ip6-privacy", self); - - /* 1.) If (and only if) the default value is not configured, check _ip6_privacy_sysctl() - * first. This is to preserve backward compatibility. In this case -- having no - * default value in global configuration, but use_tempaddr configured in /etc/sysctl -- - * the per-connection setting is always ignored. */ - if (!value) { - ip6_privacy = _ip6_privacy_sysctl (); - if (ip6_privacy != NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN) - return ip6_privacy; - } - - /* 2.) Next we always look at the per-connection setting. If it is not -1 (unknown), + /* 1.) First look at the per-connection setting. If it is not -1 (unknown), * use it. */ connection = nm_device_get_connection (self); if (connection) { @@ -4687,13 +4635,10 @@ _ip6_privacy_get (NMDevice *self) } } - /* 3.) All options (per-connection, global, sysctl) are unset/default. - * Return UNKNOWN. Skip step 5.) because that would be a change in behavior - * compared to older versions. */ - if (!value) - return NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; + value = nm_config_data_get_connection_default (nm_config_get_data (nm_config_get ()), + "ipv6.ip6-privacy", self); - /* 4.) use the default value from the configuration. */ + /* 2.) use the default value from the configuration. */ ip6_privacy = _nm_utils_ascii_str_to_int64 (value, 10, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, @@ -4701,15 +4646,8 @@ _ip6_privacy_get (NMDevice *self) if (ip6_privacy != NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN) return ip6_privacy; - /* 5.) A default-value is configured, but it is invalid/unknown. Fallback to sysctl reading. + /* 3.) No valid default-value configured. Fallback to reading sysctl. * - * _ip6_privacy_sysctl() only reads two files from /etc and does not support the complexity - * of parsing all files. Also, it only considers "net.ipv6.conf.default.use_tempaddr", - * not the per-interface values. This is kinda unexpected, but we do it in 1.) to preserve - * old behavior. - * - * Now, the user actively configured a default value to "unknown" and we can introduce new - * behavior without changing old behavior (step 1.). * Instead of reading static config files in /etc, just read the current sysctl value. * This works as NM only writes to "/proc/sys/net/ipv6/conf/IFNAME/use_tempaddr", but leaves * the "default" entry untouched. */