diff options
author | Beniamino Galvani <bgalvani@redhat.com> | 2021-06-03 09:01:23 +0200 |
---|---|---|
committer | Beniamino Galvani <bgalvani@redhat.com> | 2021-07-27 17:43:45 +0200 |
commit | bace14fe1f374db26e49e4e7d61d2fbfce4241cc (patch) | |
tree | 2c67a193b10cb4895d079881df54577f9fc9ef31 | |
parent | 604c611cd0520f97a2052f4b2f4560d09de0e738 (diff) | |
download | NetworkManager-bg/rh1934122.tar.gz |
core: introduce device 'allowed-connections' propertybg/rh1934122
Configuration can have [device*] and [connection*] settings and both
can include a 'match-device=' key, which is a list of device-specs.
Introduce a new 'allowed-connections' key for [device*] sections,
which specifies a list of connection-specs to indicate which
connections can be activated on the device.
With this, it becomes possible to have a device configuration like:
[device-enp1s0]
match-device=interface-name:enp1s0
allowed-connections=except:origin:nm-initrd-generator
so that NM in the real root ignores connections created by the
nm-initrd-generator, and starts activating a persistent
connection. This requires also setting 'keep-configuration=no' to not
generate an assumed connection.
-rw-r--r-- | man/NetworkManager.conf.xml | 19 | ||||
-rw-r--r-- | src/core/devices/nm-device.c | 11 | ||||
-rw-r--r-- | src/core/nm-config-data.c | 81 | ||||
-rw-r--r-- | src/core/nm-config-data.h | 4 | ||||
-rw-r--r-- | src/core/nm-config.c | 12 | ||||
-rw-r--r-- | src/core/settings/nm-settings.c | 10 | ||||
-rw-r--r-- | src/libnm-base/nm-config-base.h | 1 | ||||
-rw-r--r-- | src/libnm-glib-aux/nm-shared-utils.h | 1 |
8 files changed, 127 insertions, 12 deletions
diff --git a/man/NetworkManager.conf.xml b/man/NetworkManager.conf.xml index 2eba34dff2..7eaa4cb2a1 100644 --- a/man/NetworkManager.conf.xml +++ b/man/NetworkManager.conf.xml @@ -1188,6 +1188,25 @@ managed=1 </para> </listitem> </varlistentry> + <varlistentry id="allowed-connections"> + <term><varname>allowed-connections</varname></term> + <listitem> + <para> + A list of connections that can be activated on the + device. See <xref linkend="connection-spec"/> for the + syntax to specify a connection. If this option is not + specified, all connections can be potentially activated + on the device, provided that the connection type and + other settings match. + </para> + <para> + A notable use case for this is to filter which + connections can be activated based on how they were + created; see the <literal>origin</literal> keyword in + <xref linkend="connection-spec"/>. + </para> + </listitem> + </varlistentry> <varlistentry> <term><varname>wifi.scan-rand-mac-address</varname></term> <listitem> diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index f8aca987c9..cc18777a00 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -7507,6 +7507,8 @@ check_connection_compatible(NMDevice *self, NMConnection *connection, GError **e gs_free char * conn_iface = NULL; NMDeviceClass * klass; NMSettingMatch * s_match; + const GSList * specs; + gboolean has_match = FALSE; klass = NM_DEVICE_GET_CLASS(self); if (klass->connection_type_check_compatible) { @@ -7583,6 +7585,15 @@ check_connection_compatible(NMDevice *self, NMConnection *connection, GError **e } } + specs = + nm_config_data_get_device_allowed_connections_specs(NM_CONFIG_GET_DATA, self, &has_match); + if (has_match && !nm_utils_connection_match_spec_list(connection, specs, FALSE)) { + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_DISALLOWED, + "device configuration doesn't allow this connection"); + return FALSE; + } + return TRUE; } diff --git a/src/core/nm-config-data.c b/src/core/nm-config-data.c index e127ea23bb..0cbff02771 100644 --- a/src/core/nm-config-data.c +++ b/src/core/nm-config-data.c @@ -26,6 +26,15 @@ typedef struct { gboolean has; GSList * spec; } match_device; + union { + struct { + GSList * allowed_connections; + gboolean allowed_connections_has; + } device; + }; + gboolean is_device; + + /* List of key/value pairs in the section, sorted by key */ gsize lookup_len; const NMUtilsNamedValue *lookup_idx; } MatchSectionInfo; @@ -1436,13 +1445,13 @@ _match_section_infos_lookup(const MatchSectionInfo *match_section_infos, match = TRUE; if (match) { - *out_value = value; + NM_SET_OUT(out_value, value); return match_section_infos; } } out: - *out_value = NULL; + NM_SET_OUT(out_value, NULL); return NULL; } @@ -1538,6 +1547,37 @@ nm_config_data_get_device_config_int64(const NMConfigData *self, return _nm_utils_ascii_str_to_int64(value, base, min, max, val_invalid); } +const GSList * +nm_config_data_get_device_allowed_connections_specs(const NMConfigData *self, + NMDevice * device, + gboolean * has_match) +{ + const NMConfigDataPrivate *priv; + const MatchSectionInfo * connection_info; + const GSList * ret = NULL; + + g_return_val_if_fail(self, NULL); + + priv = NM_CONFIG_DATA_GET_PRIVATE(self); + + connection_info = _match_section_infos_lookup(&priv->device_infos[0], + priv->keyfile, + NM_CONFIG_KEYFILE_KEY_DEVICE_ALLOWED_CONNECTIONS, + device, + NULL, + NULL, + NULL); + + if (connection_info) { + nm_assert(connection_info->device.allowed_connections_has); + ret = connection_info->device.allowed_connections; + NM_SET_OUT(has_match, TRUE); + } else + NM_SET_OUT(has_match, FALSE); + + return ret; +} + const char * nm_config_data_get_connection_default(const NMConfigData *self, const char * property, @@ -1610,7 +1650,10 @@ _match_section_info_get_str(const MatchSectionInfo *m, GKeyFile *keyfile, const } static void -_match_section_info_init(MatchSectionInfo *connection_info, GKeyFile *keyfile, char *group) +_match_section_info_init(MatchSectionInfo *connection_info, + GKeyFile * keyfile, + char * group, + gboolean is_device) { char ** keys = NULL; gsize n_keys; @@ -1629,6 +1672,14 @@ _match_section_info_init(MatchSectionInfo *connection_info, GKeyFile *keyfile, c connection_info->stop_match = nm_config_keyfile_get_boolean(keyfile, group, NM_CONFIG_KEYFILE_KEY_STOP_MATCH, FALSE); + if (is_device) { + connection_info->device.allowed_connections = + nm_config_get_match_spec(keyfile, + group, + NM_CONFIG_KEYFILE_KEY_DEVICE_ALLOWED_CONNECTIONS, + &connection_info->device.allowed_connections_has); + } + keys = g_key_file_get_keys(keyfile, group, &n_keys, NULL); nm_utils_strv_sort(keys, n_keys); @@ -1680,9 +1731,13 @@ _match_section_infos_free(MatchSectionInfo *match_section_infos) if (!match_section_infos) return; + for (m = match_section_infos; m->group_name; m++) { g_free(m->group_name); g_slist_free_full(m->match_device.spec, g_free); + if (m->is_device) { + g_slist_free_full(m->device.allowed_connections, g_free); + } for (i = 0; i < m->lookup_len; i++) { g_free(m->lookup_idx[i].name_mutable); g_free(m->lookup_idx[i].value_str_mutable); @@ -1693,12 +1748,16 @@ _match_section_infos_free(MatchSectionInfo *match_section_infos) } static MatchSectionInfo * -_match_section_infos_construct(GKeyFile *keyfile, const char *prefix) +_match_section_infos_construct(GKeyFile *keyfile, gboolean is_device) { char ** groups; gsize i, j, ngroups; char * connection_tag = NULL; MatchSectionInfo *match_section_infos = NULL; + const char * prefix; + + prefix = + is_device ? NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE : NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION; /* get the list of existing [connection.\+]/[device.\+] sections. * @@ -1730,13 +1789,17 @@ _match_section_infos_construct(GKeyFile *keyfile, const char *prefix) } match_section_infos = g_new0(MatchSectionInfo, ngroups + 1 + (connection_tag ? 1 : 0)); + match_section_infos->is_device = is_device; for (i = 0; i < ngroups; i++) { /* pass ownership of @group on... */ - _match_section_info_init(&match_section_infos[i], keyfile, groups[ngroups - i - 1]); + _match_section_info_init(&match_section_infos[i], + keyfile, + groups[ngroups - i - 1], + is_device); } if (connection_tag) { /* pass ownership of @connection_tag on... */ - _match_section_info_init(&match_section_infos[i], keyfile, connection_tag); + _match_section_info_init(&match_section_infos[i], keyfile, connection_tag, is_device); } g_free(groups); @@ -1950,10 +2013,8 @@ constructed(GObject *object) priv->keyfile = _merge_keyfiles(priv->keyfile_user, priv->keyfile_intern); - priv->connection_infos = - _match_section_infos_construct(priv->keyfile, NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION); - priv->device_infos = - _match_section_infos_construct(priv->keyfile, NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE); + priv->connection_infos = _match_section_infos_construct(priv->keyfile, FALSE); + priv->device_infos = _match_section_infos_construct(priv->keyfile, TRUE); priv->connectivity.enabled = nm_config_keyfile_get_boolean(priv->keyfile, diff --git a/src/core/nm-config-data.h b/src/core/nm-config-data.h index 42d69a8b92..fa58d869c7 100644 --- a/src/core/nm-config-data.h +++ b/src/core/nm-config-data.h @@ -243,6 +243,10 @@ gint64 nm_config_data_get_device_config_int64(const NMConfigData *self, gint64 val_no_match, gint64 val_invalid); +const GSList *nm_config_data_get_device_allowed_connections_specs(const NMConfigData *self, + NMDevice * device, + gboolean * has_match); + char ** nm_config_data_get_groups(const NMConfigData *self); char ** nm_config_data_get_keys(const NMConfigData *self, const char *group); gboolean nm_config_data_is_intern_atomic_group(const NMConfigData *self, const char *group); diff --git a/src/core/nm-config.c b/src/core/nm-config.c index 981950ff70..817368d1cd 100644 --- a/src/core/nm-config.c +++ b/src/core/nm-config.c @@ -796,6 +796,7 @@ static gboolean _setting_is_device_spec(const char *group, const char *key) { #define _IS(group_v, key_v) (nm_streq(group, "" group_v "") && nm_streq(key, "" key_v "")) + return _IS(NM_CONFIG_KEYFILE_GROUP_MAIN, NM_CONFIG_KEYFILE_KEY_MAIN_NO_AUTO_DEFAULT) || _IS(NM_CONFIG_KEYFILE_GROUP_MAIN, NM_CONFIG_KEYFILE_KEY_MAIN_IGNORE_CARRIER) || _IS(NM_CONFIG_KEYFILE_GROUP_MAIN, NM_CONFIG_KEYFILE_KEY_MAIN_ASSUME_IPV6LL_ONLY) @@ -807,6 +808,13 @@ _setting_is_device_spec(const char *group, const char *key) } static gboolean +_setting_is_connection_spec(const char *group, const char *key) +{ + return NM_STR_HAS_PREFIX(group, NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE) + && nm_streq(key, NM_CONFIG_KEYFILE_KEY_DEVICE_ALLOWED_CONNECTIONS); +} + +static gboolean _setting_is_string_list(const char *group, const char *key) { return _IS(NM_CONFIG_KEYFILE_GROUP_MAIN, NM_CONFIG_KEYFILE_KEY_MAIN_PLUGINS) @@ -879,6 +887,7 @@ static const ConfigGroup config_groups[] = { NM_CONFIG_KEYFILE_KEY_DEVICE_MANAGED, NM_CONFIG_KEYFILE_KEY_DEVICE_SRIOV_NUM_VFS, NM_CONFIG_KEYFILE_KEY_DEVICE_KEEP_CONFIGURATION, + NM_CONFIG_KEYFILE_KEY_DEVICE_ALLOWED_CONNECTIONS, NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_BACKEND, NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_SCAN_RAND_MAC_ADDRESS, NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_SCAN_GENERATE_MAC_ADDRESS_MASK, @@ -1060,7 +1069,8 @@ read_config(GKeyFile * keyfile, is_string_list = _setting_is_string_list(group, base_key); - if (is_string_list || _setting_is_device_spec(group, base_key)) { + if (is_string_list || _setting_is_device_spec(group, base_key) + || _setting_is_connection_spec(group, base_key)) { gs_unref_ptrarray GPtrArray *new = g_ptr_array_new_with_free_func(g_free); char ** iter_val; gs_strfreev char **old_val = NULL; diff --git a/src/core/settings/nm-settings.c b/src/core/settings/nm-settings.c index 843d073e2c..8ac162d057 100644 --- a/src/core/settings/nm-settings.c +++ b/src/core/settings/nm-settings.c @@ -498,6 +498,8 @@ _startup_complete_check_is_ready(NMSettings * self, conn = nm_settings_connection_get_connection(sett_conn); nm_manager_for_each_device (priv->manager, device, tmp_lst) { + gs_free_error GError *error = NULL; + if (!nm_device_is_real(device)) continue; @@ -508,7 +510,13 @@ _startup_complete_check_is_ready(NMSettings * self, continue; } - if (!nm_device_check_connection_compatible(device, conn, NULL)) + /* Check that device is compatible with the device. We are also happy + * with a device compatible but for which the connection is disallowed + * by NM configuration. */ + if (!nm_device_check_connection_compatible(device, conn, &error) + && !g_error_matches(error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_DISALLOWED)) continue; return TRUE; diff --git a/src/libnm-base/nm-config-base.h b/src/libnm-base/nm-config-base.h index 9ef5d7f846..c413e867ea 100644 --- a/src/libnm-base/nm-config-base.h +++ b/src/libnm-base/nm-config-base.h @@ -63,6 +63,7 @@ #define NM_CONFIG_KEYFILE_KEY_DEVICE_IGNORE_CARRIER "ignore-carrier" #define NM_CONFIG_KEYFILE_KEY_DEVICE_SRIOV_NUM_VFS "sriov-num-vfs" #define NM_CONFIG_KEYFILE_KEY_DEVICE_KEEP_CONFIGURATION "keep-configuration" +#define NM_CONFIG_KEYFILE_KEY_DEVICE_ALLOWED_CONNECTIONS "allowed-connections" #define NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_BACKEND "wifi.backend" #define NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_SCAN_RAND_MAC_ADDRESS "wifi.scan-rand-mac-address" #define NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_SCAN_GENERATE_MAC_ADDRESS_MASK \ diff --git a/src/libnm-glib-aux/nm-shared-utils.h b/src/libnm-glib-aux/nm-shared-utils.h index 8d12f05ef5..ac522e6d21 100644 --- a/src/libnm-glib-aux/nm-shared-utils.h +++ b/src/libnm-glib-aux/nm-shared-utils.h @@ -1274,6 +1274,7 @@ typedef enum { NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_DISALLOWED, NM_UTILS_ERROR_SETTING_MISSING, |