diff options
Diffstat (limited to 'src/libnm-core-impl')
28 files changed, 2095 insertions, 296 deletions
diff --git a/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in b/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in index 6d2b9254..e0ce4ac4 100644 --- a/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in +++ b/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in @@ -826,6 +826,18 @@ dbus-type="s" gprop-type="gchararray" /> + <property name="ip-ping-addresses" + dbus-type="as" + gprop-type="GStrv" + /> + <property name="ip-ping-addresses-require-all" + dbus-type="i" + gprop-type="gint" + /> + <property name="ip-ping-timeout" + dbus-type="u" + gprop-type="guint" + /> <property name="lldp" dbus-type="i" gprop-type="gint" @@ -1349,6 +1361,10 @@ dbus-type="u" is-setting-option="1" /> + <property name="fec-mode" + dbus-type="u" + is-setting-option="1" + /> </setting> <setting name="generic" gtype="NMSettingGeneric" @@ -1389,6 +1405,44 @@ dbus-type="b" gprop-type="gboolean" /> + <property name="initial-eps-bearer-noauth" + dbus-type="b" + gprop-type="gboolean" + /> + <property name="initial-eps-bearer-password" + is-secret="1" + dbus-type="s" + gprop-type="gchararray" + /> + <property name="initial-eps-bearer-password-flags" + is-secret-flags="1" + dbus-type="u" + gprop-type="NMSettingSecretFlags" + /> + <property name="initial-eps-bearer-refuse-chap" + dbus-type="b" + gprop-type="gboolean" + /> + <property name="initial-eps-bearer-refuse-eap" + dbus-type="b" + gprop-type="gboolean" + /> + <property name="initial-eps-bearer-refuse-mschap" + dbus-type="b" + gprop-type="gboolean" + /> + <property name="initial-eps-bearer-refuse-mschapv2" + dbus-type="b" + gprop-type="gboolean" + /> + <property name="initial-eps-bearer-refuse-pap" + dbus-type="b" + gprop-type="gboolean" + /> + <property name="initial-eps-bearer-username" + dbus-type="s" + gprop-type="gchararray" + /> <property name="mtu" dbus-type="u" gprop-type="guint" @@ -1610,6 +1664,10 @@ dbus-type="s" gprop-type="gchararray" /> + <property name="dhcp-ipv6-only-preferred" + dbus-type="i" + gprop-type="gint" + /> <property name="dhcp-reject-servers" dbus-type="as" gprop-type="GStrv" @@ -1618,6 +1676,10 @@ dbus-type="b" gprop-type="gboolean" /> + <property name="dhcp-send-hostname-v2" + dbus-type="i" + gprop-type="gint" + /> <property name="dhcp-send-release" dbus-type="i" gprop-type="NMTernary" @@ -1697,6 +1759,10 @@ dbus-type="u" gprop-type="guint" /> + <property name="routed-dns" + dbus-type="i" + gprop-type="gint" + /> <property name="routes" dbus-type="aau" dbus-deprecated="1" @@ -1705,6 +1771,14 @@ <property name="routing-rules" dbus-type="aa{sv}" /> + <property name="shared-dhcp-lease-time" + dbus-type="i" + gprop-type="gint" + /> + <property name="shared-dhcp-range" + dbus-type="s" + gprop-type="gchararray" + /> </setting> <setting name="ipv6" gtype="NMSettingIP6Config" @@ -1761,6 +1835,10 @@ dbus-type="b" gprop-type="gboolean" /> + <property name="dhcp-send-hostname-v2" + dbus-type="i" + gprop-type="gint" + /> <property name="dhcp-send-release" dbus-type="i" gprop-type="NMTernary" @@ -1844,6 +1922,10 @@ dbus-type="u" gprop-type="guint" /> + <property name="routed-dns" + dbus-type="i" + gprop-type="gint" + /> <property name="routes" dbus-type="a(ayuayu)" dbus-deprecated="1" @@ -1852,6 +1934,14 @@ <property name="routing-rules" dbus-type="aa{sv}" /> + <property name="shared-dhcp-lease-time" + dbus-type="i" + gprop-type="gint" + /> + <property name="shared-dhcp-range" + dbus-type="s" + gprop-type="gchararray" + /> <property name="temp-preferred-lifetime" dbus-type="i" gprop-type="gint" @@ -1865,6 +1955,26 @@ gprop-type="gchararray" /> </setting> + <setting name="ipvlan" + gtype="NMSettingIpvlan" + > + <property name="mode" + dbus-type="u" + gprop-type="guint" + /> + <property name="parent" + dbus-type="s" + gprop-type="gchararray" + /> + <property name="private" + dbus-type="b" + gprop-type="gboolean" + /> + <property name="vepa" + dbus-type="b" + gprop-type="gboolean" + /> + </setting> <setting name="link" gtype="NMSettingLink" > diff --git a/src/libnm-core-impl/meson.build b/src/libnm-core-impl/meson.build index e1f11f32..e068d6bd 100644 --- a/src/libnm-core-impl/meson.build +++ b/src/libnm-core-impl/meson.build @@ -25,6 +25,7 @@ libnm_core_settings_sources = files( 'nm-setting-ip-tunnel.c', 'nm-setting-ip4-config.c', 'nm-setting-ip6-config.c', + 'nm-setting-ipvlan.c', 'nm-setting-link.c', 'nm-setting-loopback.c', 'nm-setting-macsec.c', diff --git a/src/libnm-core-impl/nm-connection-private.h b/src/libnm-core-impl/nm-connection-private.h index 9f9007b6..38619bd7 100644 --- a/src/libnm-core-impl/nm-connection-private.h +++ b/src/libnm-core-impl/nm-connection-private.h @@ -29,6 +29,10 @@ const char *_nm_connection_detect_bluetooth_type(NMConnection *self); gboolean _nm_setting_connection_verify_secondaries(GArray *secondaries, GError **error); +gboolean _nm_setting_connection_verify_no_duplicate_addresses(GArray *secondaries, GError **error); + +int _get_ip_address_family(const char *ip_address); + gboolean _nm_connection_verify_required_interface_name(NMConnection *connection, GError **error); int _nm_setting_ovs_interface_verify_interface_type(NMSettingOvsInterface *self, diff --git a/src/libnm-core-impl/nm-connection.c b/src/libnm-core-impl/nm-connection.c index 6dace2b7..61a20a13 100644 --- a/src/libnm-core-impl/nm-connection.c +++ b/src/libnm-core-impl/nm-connection.c @@ -89,7 +89,7 @@ _nm_connection_get_private_from_qdata(NMConnection *connection) priv = g_object_get_qdata((GObject *) connection, key); if (G_UNLIKELY(!priv)) { priv = g_slice_new(NMConnectionPrivate); - *priv = (NMConnectionPrivate){ + *priv = (NMConnectionPrivate) { .self = connection, }; g_object_set_qdata_full((GObject *) connection, key, priv, _nm_connection_private_free); @@ -959,6 +959,40 @@ out: return FALSE; } +gboolean +_nm_setting_connection_verify_no_duplicate_addresses(GArray *addresses, GError **error) +{ + guint i, j; + + if (addresses->len <= 1) { + return TRUE; + } else { + for (i = 0; i < addresses->len - 1; i++) { + for (j = i + 1; j < addresses->len; j++) { + if (nm_streq0(nm_g_array_index(addresses, const char *, i), + nm_g_array_index(addresses, const char *, j))) + return FALSE; + } + } + } + + return TRUE; +} + +int +_get_ip_address_family(const char *ip_address) +{ + struct in_addr ipv4_addr; + struct in6_addr ipv6_addr; + + if (inet_pton(AF_INET, ip_address, &ipv4_addr)) + return AF_INET; + else if (inet_pton(AF_INET6, ip_address, &ipv6_addr)) + return AF_INET6; + else + return -1; +} + static gboolean _normalize_connection_secondaries(NMConnection *self) { @@ -998,6 +1032,48 @@ _normalize_connection_secondaries(NMConnection *self) } static gboolean +_normalize_connection_ip_ping_addresses(NMConnection *self) +{ + NMSettingConnection *s_con = nm_connection_get_setting_connection(self); + GArray *addresses; + gs_strfreev char **strv = NULL; + guint i, j, k; + + nm_assert(s_con); + + addresses = _nm_setting_connection_get_ip_ping_addresses(s_con); + if (nm_g_array_len(addresses) == 0) + return FALSE; + + if (_nm_setting_connection_verify_no_duplicate_addresses(addresses, NULL)) + return FALSE; + + strv = nm_strvarray_get_strv_notempty_dup(addresses, NULL); + + for (i = 0, j = 0; strv[i]; i++) { + gboolean found = FALSE; + + for (k = 0; k < j; k++) { + if (nm_streq0(strv[i], strv[k])) { + found = TRUE; + break; + } + } + + if (found) { + continue; + } + + strv[j++] = strv[i]; + } + strv[j] = NULL; + + g_object_set(s_con, NM_SETTING_CONNECTION_IP_PING_ADDRESSES, strv, NULL); + + return TRUE; +} + +static gboolean _normalize_connection_type(NMConnection *self) { NMSettingConnection *s_con = nm_connection_get_setting_connection(self); @@ -1186,6 +1262,7 @@ _normalize_ip_config(NMConnection *self, GHashTable *parameters) NMSetting *setting; gboolean changed = FALSE; guint num, i; + int dhcp_send_hostname_v2; s_ip4 = nm_connection_get_setting_ip4_config(self); s_ip6 = nm_connection_get_setting_ip6_config(self); @@ -1241,6 +1318,16 @@ _normalize_ip_config(NMConnection *self, GHashTable *parameters) nm_setting_ip_config_remove_address(s_ip4, i); changed = TRUE; } + + dhcp_send_hostname_v2 = nm_setting_ip_config_get_dhcp_send_hostname_v2(s_ip4); + if (dhcp_send_hostname_v2 != NM_TERNARY_DEFAULT + && dhcp_send_hostname_v2 != nm_setting_ip_config_get_dhcp_send_hostname(s_ip4)) { + g_object_set(s_ip4, + NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME, + dhcp_send_hostname_v2, + NULL); + changed = TRUE; + } } } else { if (s_ip4) { @@ -1315,6 +1402,16 @@ _normalize_ip_config(NMConnection *self, GHashTable *parameters) g_object_set(s_ip6, NM_SETTING_IP_CONFIG_MAY_FAIL, TRUE, NULL); changed = TRUE; } + + dhcp_send_hostname_v2 = nm_setting_ip_config_get_dhcp_send_hostname_v2(s_ip6); + if (dhcp_send_hostname_v2 != NM_TERNARY_DEFAULT + && dhcp_send_hostname_v2 != nm_setting_ip_config_get_dhcp_send_hostname(s_ip6)) { + g_object_set(s_ip6, + NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME, + dhcp_send_hostname_v2, + NULL); + changed = TRUE; + } } } else { if (s_ip6) { @@ -2028,6 +2125,7 @@ _connection_normalize(NMConnection *connection, was_modified |= _normalize_connection_type(connection); was_modified |= _normalize_connection_port_type(connection); was_modified |= _normalize_connection_secondaries(connection); + was_modified |= _normalize_connection_ip_ping_addresses(connection); was_modified |= _normalize_connection(connection); was_modified |= _normalize_required_settings(connection); was_modified |= _normalize_invalid_port_port_settings(connection); @@ -3176,6 +3274,7 @@ nm_connection_is_virtual(NMConnection *connection) NM_SETTING_DUMMY_SETTING_NAME, NM_SETTING_HSR_SETTING_NAME, NM_SETTING_IP_TUNNEL_SETTING_NAME, + NM_SETTING_IPVLAN_SETTING_NAME, NM_SETTING_MACSEC_SETTING_NAME, NM_SETTING_MACVLAN_SETTING_NAME, NM_SETTING_OVS_BRIDGE_SETTING_NAME, diff --git a/src/libnm-core-impl/nm-keyfile-utils.c b/src/libnm-core-impl/nm-keyfile-utils.c index 95073bcc..fdf00677 100644 --- a/src/libnm-core-impl/nm-keyfile-utils.c +++ b/src/libnm-core-impl/nm-keyfile-utils.c @@ -682,22 +682,3 @@ nm_keyfile_key_decode(const char *key, char **out_to_free) #endif return name; } - -void -nm_keyfile_add_group(GKeyFile *keyfile, const char *group) -{ - nm_assert(keyfile); - nm_assert(group); - - /* You can only call this function if the group doesn't exist yet. - * Because, we are about to add a dummy key, so we would have to - * be sure that the key doesn't exist. */ - nm_assert(!g_key_file_has_group(keyfile, group)); - - /* Ensure the group is present. - * There is no API for that, so add and remove a dummy key. - * For a profile it matters whether a setting is present or not, - * and we need to ensure that we persist the presence of the setting to keyfile*/ - g_key_file_set_value(keyfile, group, ".X", "1"); - g_key_file_remove_key(keyfile, group, ".X", NULL); -} diff --git a/src/libnm-core-impl/nm-keyfile.c b/src/libnm-core-impl/nm-keyfile.c index 8dadf3cd..e4559e3c 100644 --- a/src/libnm-core-impl/nm-keyfile.c +++ b/src/libnm-core-impl/nm-keyfile.c @@ -18,6 +18,7 @@ #include <linux/if_ether.h> #include <linux/if_infiniband.h> +#include "libnm-glib-aux/nm-keyfile-aux.h" #include "libnm-glib-aux/nm-uuid.h" #include "libnm-glib-aux/nm-str-buf.h" #include "libnm-glib-aux/nm-secret-utils.h" @@ -132,7 +133,7 @@ _nm_printf(5, 6) static void _read_handle_warn(KeyfileReaderInfo *info, info, kf_key, cur_property); - handler_data.warn = (NMKeyfileHandlerDataWarn){ + handler_data.warn = (NMKeyfileHandlerDataWarn) { .severity = severity, .message = NULL, .fmt = fmt, @@ -186,7 +187,7 @@ _nm_printf(6, 7) static void _write_handle_warn(KeyfileWriterInfo *info, cur_property, setting, kf_key); - handler_data.warn = (NMKeyfileHandlerDataWarn){ + handler_data.warn = (NMKeyfileHandlerDataWarn) { .severity = severity, .message = NULL, .fmt = fmt, @@ -915,7 +916,7 @@ _build_list_create(GKeyFile *keyfile, if (G_UNLIKELY(!build_list)) build_list = g_new(BuildListData, n_keys - i_keys); - build_list[build_list_len++] = (BuildListData){ + build_list[build_list_len++] = (BuildListData) { .s_key = s_key, .key_idx = key_idx, .key_type = key_type, @@ -939,6 +940,31 @@ _build_list_create(GKeyFile *keyfile, } static void +gateway_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) +{ + const char *setting_name = nm_setting_get_name(setting); + gs_free char *gateway = NULL; + const char *old_gateway; + + gateway = nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, key, NULL); + if (!gateway) + return; + + old_gateway = nm_setting_ip_config_get_gateway(NM_SETTING_IP_CONFIG(setting)); + if (old_gateway && !nm_streq0(gateway, old_gateway)) { + read_handle_warn(info, + key, + NM_SETTING_IP_CONFIG_GATEWAY, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("ignoring gateway \"%s\" from \"address*\" keys because the " + "\"gateway\" key is set"), + old_gateway); + } + + g_object_set(setting, NM_SETTING_IP_CONFIG_GATEWAY, gateway, NULL); +} + +static void ip_address_or_route_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *setting_key) { const char *setting_name = nm_setting_get_name(setting); @@ -1132,7 +1158,7 @@ ip_dns_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) addr_family = NM_SETTING_IP_CONFIG_GET_ADDR_FAMILY(setting); for (i = 0, n = 0; i < length; i++) { - if (!nm_utils_dnsname_parse(addr_family, list[i], NULL, NULL, NULL)) { + if (!nm_dns_uri_parse(addr_family, list[i], NULL)) { if (!read_handle_warn(info, key, key, @@ -2263,11 +2289,7 @@ ip6_addr_gen_mode_writer(KeyfileWriterInfo *info, } static void -write_ip_values(GKeyFile *file, - const char *setting_name, - GPtrArray *array, - const char *gateway, - gboolean is_route) +write_ip_values(GKeyFile *file, const char *setting_name, GPtrArray *array, gboolean is_route) { if (array->len > 0) { nm_auto_str_buf NMStrBuf output = NM_STR_BUF_INIT(2 * INET_ADDRSTRLEN + 10, FALSE); @@ -2300,7 +2322,7 @@ write_ip_values(GKeyFile *file, addr = nm_ip_address_get_address(address); plen = nm_ip_address_get_prefix(address); - gw = (i == 0) ? gateway : NULL; + gw = NULL; } nm_str_buf_set_size(&output, 0, FALSE, FALSE); @@ -2351,11 +2373,10 @@ addr_writer(KeyfileWriterInfo *info, NMSetting *setting, const char *key, const { GPtrArray *array; const char *setting_name = nm_setting_get_name(setting); - const char *gateway = nm_setting_ip_config_get_gateway(NM_SETTING_IP_CONFIG(setting)); array = (GPtrArray *) g_value_get_boxed(value); if (array && array->len) - write_ip_values(info->keyfile, setting_name, array, gateway, FALSE); + write_ip_values(info->keyfile, setting_name, array, FALSE); } static void @@ -2366,7 +2387,7 @@ route_writer(KeyfileWriterInfo *info, NMSetting *setting, const char *key, const array = (GPtrArray *) g_value_get_boxed(value); if (array && array->len) - write_ip_values(info->keyfile, setting_name, array, NULL, TRUE); + write_ip_values(info->keyfile, setting_name, array, TRUE); } static void @@ -2482,7 +2503,7 @@ wired_s390_options_writer_full(KeyfileWriterInfo *info, /* groups in the keyfile are ordered. When we are about to add [ethernet-s390-options], * we want to also have an [ethernet] group, first. */ - nm_keyfile_add_group(info->keyfile, setting_alias ?: NM_SETTING_WIRED_SETTING_NAME); + nm_key_file_add_group(info->keyfile, setting_alias ?: NM_SETTING_WIRED_SETTING_NAME); } for (i = 0; i < n; i++) { @@ -2882,7 +2903,7 @@ cert_writer(KeyfileWriterInfo *info, NMSetting *setting, const char *key, const vtable->setting_key, setting, key); - handler_data.write_cert = (NMKeyfileHandlerDataWriteCert){ + handler_data.write_cert = (NMKeyfileHandlerDataWriteCert) { .vtable = vtable, }; @@ -2944,11 +2965,11 @@ struct _ParseInfoProperty { }; #define PARSE_INFO_PROPERTY(_property_name, ...) \ - (&((const ParseInfoProperty){.property_name = _property_name, __VA_ARGS__})) + (&((const ParseInfoProperty) {.property_name = _property_name, __VA_ARGS__})) -#define PARSE_INFO_PROPERTIES(...) \ - .properties = ((const ParseInfoProperty *const[]){ \ - __VA_ARGS__ NULL, \ +#define PARSE_INFO_PROPERTIES(...) \ + .properties = ((const ParseInfoProperty *const[]) { \ + __VA_ARGS__ NULL, \ }) typedef struct { @@ -2956,7 +2977,7 @@ typedef struct { } ParseInfoSetting; #define PARSE_INFO_SETTING(setting_type, ...) \ - [setting_type] = (&((const ParseInfoSetting){__VA_ARGS__})) + [setting_type] = (&((const ParseInfoSetting) {__VA_ARGS__})) static const ParseInfoSetting *const parse_infos[_NM_META_SETTING_TYPE_NUM] = { PARSE_INFO_SETTING( @@ -3060,7 +3081,7 @@ static const ParseInfoSetting *const parse_infos[_NM_META_SETTING_TYPE_NUM] = { .parser = ip_dns_parser, .writer = dns_writer, ), PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_DNS_OPTIONS, .always_write = TRUE, ), - PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_GATEWAY, .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_GATEWAY, .parser = gateway_parser, ), PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_ROUTES, .parser_no_check_key = TRUE, .parser = ip_address_or_route_parser, @@ -3088,7 +3109,7 @@ static const ParseInfoSetting *const parse_infos[_NM_META_SETTING_TYPE_NUM] = { .parser = ip_dns_parser, .writer = dns_writer, ), PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_DNS_OPTIONS, .always_write = TRUE, ), - PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_GATEWAY, .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_GATEWAY, .parser = gateway_parser, ), PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_ROUTES, .parser_no_check_key = TRUE, .parser = ip_address_or_route_parser, @@ -3549,6 +3570,62 @@ read_one_setting_value(KeyfileReaderInfo *info, } static void +_read_handle_renamed_properties(KeyfileReaderInfo *info) +{ + GKeyFile *kf = info->keyfile; + const char *group = info->group; + gs_free_error GError *error = NULL; + + if (NM_IN_STRSET(group, "ipv4", "ipv6")) { + /* dhcp-send-hostname is stored as dhcp-send-hostname-deprecated + * dhcp-send-hostname-v2 is stored as dhcp-send-hostname + * Do the conversion back. Also, accept boolean values for -v2 to + * maintain backwards compatibility with keyfiles written with the + * deprecated property in mind + */ + if (g_key_file_has_key(kf, group, "dhcp-send-hostname", NULL)) { + gboolean val_bool; + int val; + + val = g_key_file_get_integer(kf, group, "dhcp-send-hostname", &error); + if (error) { + g_clear_error(&error); + val_bool = g_key_file_get_boolean(kf, group, "dhcp-send-hostname", &error); + if (!error) + val = val_bool ? 1 : 0; + else + read_handle_warn(info, + NULL, + NULL, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid value for '%s.dhcp-send-hostname'"), + info->group); + } + + g_key_file_remove_key(kf, group, "dhcp-send-hostname", NULL); + if (!error) + g_key_file_set_integer(kf, group, "dhcp-send-hostname-v2", val); + } + + if (g_key_file_has_key(kf, group, "dhcp-send-hostname-deprecated", NULL)) { + gs_free char *val = NULL; + + val = g_key_file_get_value(kf, group, "dhcp-send-hostname-deprecated", NULL); + g_key_file_remove_key(kf, group, "dhcp-send-hostname-deprecated", NULL); + if (val) + g_key_file_set_value(kf, group, "dhcp-send-hostname", val); + else + read_handle_warn(info, + NULL, + NULL, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid value for '%s.dhcp-send-hostname-deprecated'"), + info->group); + } + } +} + +static void _read_setting(KeyfileReaderInfo *info) { const NMSettInfoSetting *sett_info; @@ -3576,6 +3653,8 @@ _read_setting(KeyfileReaderInfo *info) info->setting = setting; + _read_handle_renamed_properties(info); + sett_info = _nm_setting_class_get_sett_info(NM_SETTING_GET_CLASS(setting)); if (sett_info->detail.gendata_info) { @@ -3950,7 +4029,7 @@ nm_keyfile_read(GKeyFile *keyfile, connection = nm_simple_connection_new(); - info = (KeyfileReaderInfo){ + info = (KeyfileReaderInfo) { .connection = connection, .keyfile = keyfile, .base_dir = base_dir, @@ -4084,11 +4163,23 @@ write_setting_value(KeyfileWriterInfo *info, NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST)) return; - value = (GValue){0}; + value = (GValue) {0}; g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(property_info->param_spec)); g_object_get_property(G_OBJECT(setting), property_info->param_spec->name, &value); + /* To prevent any confusion from the user regarding the v2 suffix, + * dhcp-send-hostname is stored as dhcp-send-hostname-deprecated + * and dhcp-send-hostname-v2 is stored as dhcp-send-hostname + * in the keyfile. + */ + if (NM_IS_SETTING_IP4_CONFIG(setting) || NM_IS_SETTING_IP6_CONFIG(setting)) { + if (nm_streq(key, NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME_V2)) + key = "dhcp-send-hostname"; + else if (nm_streq(key, NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME)) + key = "dhcp-send-hostname-deprecated"; + } + if ((!pip || !pip->writer_persist_default) && g_param_value_defaults(property_info->param_spec, &value)) { nm_assert(!g_key_file_has_key(info->keyfile, setting_info->setting_name, key, NULL)); @@ -4304,7 +4395,7 @@ nm_keyfile_write(NMConnection *connection, keyfile = g_key_file_new(); - info = (KeyfileWriterInfo){ + info = (KeyfileWriterInfo) { .connection = connection, .keyfile = keyfile, .error = NULL, @@ -4385,7 +4476,7 @@ nm_keyfile_write(NMConnection *connection, || g_key_file_has_group(info.keyfile, setting_name)) { /* we have a section for the setting. Nothing to do. */ } else { - nm_keyfile_add_group(info.keyfile, setting_alias ?: setting_name); + nm_key_file_add_group(info.keyfile, setting_alias ?: setting_name); } if (NM_IS_SETTING_WIREGUARD(setting)) { diff --git a/src/libnm-core-impl/nm-meta-setting-base-impl.c b/src/libnm-core-impl/nm-meta-setting-base-impl.c index 34a7d22e..37cb61f1 100644 --- a/src/libnm-core-impl/nm-meta-setting-base-impl.c +++ b/src/libnm-core-impl/nm-meta-setting-base-impl.c @@ -35,6 +35,7 @@ #include "nm-setting-ip-tunnel.h" #include "nm-setting-ip4-config.h" #include "nm-setting-ip6-config.h" +#include "nm-setting-ipvlan.h" #include "nm-setting-link.h" #include "nm-setting-loopback.h" #include "nm-setting-macsec.h" @@ -371,6 +372,13 @@ const NMMetaSettingInfo nm_meta_setting_infos[] = { .setting_name = NM_SETTING_IP_TUNNEL_SETTING_NAME, .get_setting_gtype = nm_setting_ip_tunnel_get_type, }, + [NM_META_SETTING_TYPE_IPVLAN] = + { + .meta_type = NM_META_SETTING_TYPE_IPVLAN, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_IPVLAN_SETTING_NAME, + .get_setting_gtype = nm_setting_ipvlan_get_type, + }, [NM_META_SETTING_TYPE_LINK] = { .meta_type = NM_META_SETTING_TYPE_LINK, @@ -643,6 +651,7 @@ const NMMetaSettingType nm_meta_setting_types_by_priority[] = { NM_META_SETTING_TYPE_HSR, NM_META_SETTING_TYPE_INFINIBAND, NM_META_SETTING_TYPE_IP_TUNNEL, + NM_META_SETTING_TYPE_IPVLAN, NM_META_SETTING_TYPE_LOOPBACK, NM_META_SETTING_TYPE_MACSEC, NM_META_SETTING_TYPE_MACVLAN, @@ -822,7 +831,7 @@ again: for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) { const NMMetaSettingInfo *m = &nm_meta_setting_infos[i]; - static_array[i] = (LookupData){ + static_array[i] = (LookupData) { .gtype = m->get_setting_gtype(), .setting_info = m, }; diff --git a/src/libnm-core-impl/nm-setting-bridge.c b/src/libnm-core-impl/nm-setting-bridge.c index 7e9a0964..c1618434 100644 --- a/src/libnm-core-impl/nm-setting-bridge.c +++ b/src/libnm-core-impl/nm-setting-bridge.c @@ -151,7 +151,7 @@ nm_bridge_vlan_new(guint16 vid_start, guint16 vid_end) g_return_val_if_fail(vid_start <= vid_end, NULL); vlan = g_slice_new(NMBridgeVlan); - *vlan = (NMBridgeVlan){ + *vlan = (NMBridgeVlan) { .refcount = 1, .vid_start = vid_start, .vid_end = vid_end, diff --git a/src/libnm-core-impl/nm-setting-connection.c b/src/libnm-core-impl/nm-setting-connection.c index 33d088bb..4a910c7f 100644 --- a/src/libnm-core-impl/nm-setting-connection.c +++ b/src/libnm-core-impl/nm-setting-connection.c @@ -63,6 +63,9 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMSettingConnection, PROP_AUTOCONNECT_PORTS, PROP_SECONDARIES, PROP_GATEWAY_PING_TIMEOUT, + PROP_IP_PING_TIMEOUT, + PROP_IP_PING_ADDRESSES, + PROP_IP_PING_ADDRESSES_REQUIRE_ALL, PROP_METERED, PROP_LLDP, PROP_MDNS, @@ -91,6 +94,7 @@ typedef struct { guint64 timestamp; int autoconnect_ports; int down_on_poweroff; + int ip_ping_addresses_require_all; int metered; gint32 autoconnect_priority; gint32 autoconnect_retries; @@ -104,6 +108,8 @@ typedef struct { gint32 wait_activation_delay; guint32 mptcp_flags; guint32 gateway_ping_timeout; + NMValueStrv ip_ping_addresses; + guint32 ip_ping_timeout; bool autoconnect; bool read_only; } NMSettingConnectionPrivate; @@ -139,7 +145,7 @@ _permission_set_stale(Permission *permission, PermType ptype, char *item_take) /* we don't inspect (clear) permission before setting. It takes a * stale instance. */ - *permission = (Permission){ + *permission = (Permission) { .ptype = ptype, .item = item_take, }; @@ -1037,6 +1043,172 @@ nm_setting_connection_get_gateway_ping_timeout(NMSettingConnection *setting) return NM_SETTING_CONNECTION_GET_PRIVATE(setting)->gateway_ping_timeout; } +GArray * +_nm_setting_connection_get_ip_ping_addresses(NMSettingConnection *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_CONNECTION(setting), NULL); + + return NM_SETTING_CONNECTION_GET_PRIVATE(setting)->ip_ping_addresses.arr; +} + +/** + * nm_setting_connection_get_ip_ping_address: + * @setting: the #NMSettingConnection + * @idx: the zero-based index of the ip-ping-addresses entry. + * + * Returns: the ip address string at index @idx or + * %NULL if @idx is the number of ip-ping-addresses. + * + * Since: 1.52 + **/ +const char * +nm_setting_connection_get_ip_ping_address(NMSettingConnection *setting, guint32 idx) +{ + g_return_val_if_fail(NM_IS_SETTING_CONNECTION(setting), NULL); + + return nm_strvarray_get_idxnull_or_greturn( + NM_SETTING_CONNECTION_GET_PRIVATE(setting)->ip_ping_addresses.arr, + idx); +} + +/** + * nm_setting_connection_add_ip_ping_address: + * @setting: the #NMSettingConnection + * @address: the IP address string to add + * + * Adds a new IP address string to the ip-ping-addresses. + * + * Returns: %TRUE if the new IP address was added; %FALSE if the IP address + * was already present + * + * Since: 1.52 + **/ +gboolean +nm_setting_connection_add_ip_ping_address(NMSettingConnection *setting, const char *address) +{ + NMSettingConnectionPrivate *priv; + + g_return_val_if_fail(NM_IS_SETTING_CONNECTION(setting), FALSE); + g_return_val_if_fail(address, FALSE); + + priv = NM_SETTING_CONNECTION_GET_PRIVATE(setting); + + if (!nm_strvarray_ensure_and_add_unique(&priv->ip_ping_addresses.arr, address)) + return FALSE; + + _notify(setting, PROP_IP_PING_ADDRESSES); + return TRUE; +} + +/** + * nm_setting_connection_remove_ip_ping_address: + * @setting: the #NMSettingConnection + * @idx: index number of the IP address + * + * Removes the IP address at index @idx. + * + * Since: 1.52 + **/ +void +nm_setting_connection_remove_ip_ping_address(NMSettingConnection *setting, guint32 idx) +{ + NMSettingConnectionPrivate *priv; + + g_return_if_fail(NM_IS_SETTING_CONNECTION(setting)); + + priv = NM_SETTING_CONNECTION_GET_PRIVATE(setting); + + g_return_if_fail(idx < nm_g_array_len(priv->ip_ping_addresses.arr)); + + nm_strvarray_remove_index(priv->ip_ping_addresses.arr, idx); + _notify(setting, PROP_IP_PING_ADDRESSES); +} + +/** + * nm_setting_connection_remove_ip_ping_address_by_value: + * @setting: the #NMSettingConnection + * @address: the IP address to remove + * + * Removes the IP address @address from ip-ping-addresses. + * + * Returns: %TRUE if the IP address was found and removed; %FALSE if it was not. + * + * Since: 1.52 + **/ +gboolean +nm_setting_connection_remove_ip_ping_address_by_value(NMSettingConnection *setting, + const char *address) +{ + NMSettingConnectionPrivate *priv; + + g_return_val_if_fail(NM_IS_SETTING_CONNECTION(setting), FALSE); + g_return_val_if_fail(address, FALSE); + + priv = NM_SETTING_CONNECTION_GET_PRIVATE(setting); + + if (!nm_strvarray_remove_first(priv->ip_ping_addresses.arr, address)) + return FALSE; + + _notify(setting, PROP_IP_PING_ADDRESSES); + return TRUE; +} + +/** + * nm_setting_connection_clear_ip_ping_addresses: + * @setting: the #NMSettingConnection + * + * Removes all configured ip-ping-addresses. + * + * Since: 1.52 + **/ +void +nm_setting_connection_clear_ip_ping_addresses(NMSettingConnection *setting) +{ + NMSettingConnectionPrivate *priv; + + g_return_if_fail(NM_IS_SETTING_CONNECTION(setting)); + + priv = NM_SETTING_CONNECTION_GET_PRIVATE(setting); + + if (nm_strvarray_clear(&priv->ip_ping_addresses.arr)) + _notify(setting, PROP_IP_PING_ADDRESSES); +} + +/** + * nm_setting_connection_get_ip_ping_timeout: + * @setting: the #NMSettingConnection + * + * Returns: the value contained in the #NMSettingConnection:ip-ping-timeout + * property. + * + * Since: 1.52 + **/ +guint32 +nm_setting_connection_get_ip_ping_timeout(NMSettingConnection *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_CONNECTION(setting), 0); + + return NM_SETTING_CONNECTION_GET_PRIVATE(setting)->ip_ping_timeout; +} + +/** + * nm_setting_connection_get_ip_ping_addresses_require_all: + * @setting: the #NMSettingConnection + * + * Returns the #NMSettingConnection:ip-ping-addresses-require-all property of the connection. + * + * Returns: whether all the ip ping addresses pass the connectivity check. + * + * Since: 1.52 + **/ +NMTernary +nm_setting_connection_get_ip_ping_addresses_require_all(NMSettingConnection *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_CONNECTION(setting), NM_TERNARY_DEFAULT); + + return NM_SETTING_CONNECTION_GET_PRIVATE(setting)->ip_ping_addresses_require_all; +} + /** * nm_setting_connection_get_metered: * @setting: the #NMSettingConnection @@ -1610,6 +1782,176 @@ after_interface_name: } } + if (priv->ip_ping_timeout != 0 + && (!priv->ip_ping_addresses.arr || priv->ip_ping_addresses.arr->len == 0)) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("can only be set if %s.%s is set"), + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_IP_PING_ADDRESSES); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_IP_PING_TIMEOUT); + return FALSE; + } + + if (priv->ip_ping_addresses.arr && priv->ip_ping_addresses.arr->len > 0) { + guint i; + + if (priv->ip_ping_timeout == 0) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("can only be set if %s.%s is set"), + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_IP_PING_TIMEOUT); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_IP_PING_ADDRESSES); + return FALSE; + } + + if (priv->gateway_ping_timeout != 0 && priv->ip_ping_timeout != 0) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("is incompatible with '%s'"), + NM_SETTING_CONNECTION_IP_PING_TIMEOUT); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT); + return FALSE; + } + + for (i = 0; i < priv->ip_ping_addresses.arr->len; i++) { + const char *address = nm_g_array_index(priv->ip_ping_addresses.arr, const char *, i); + int addr_family = _get_ip_address_family(address); + + if (addr_family == AF_INET) { + NMSettingIPConfig *s_ip4; + + if (connection) { + s_ip4 = nm_connection_get_setting_ip4_config(connection); + + if (s_ip4) { + const char *method = nm_setting_ip_config_get_method(s_ip4); + if (nm_streq0(method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("contains IPv4 address '%s', %s.%s cannot be 'disabled'"), + address, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP_CONFIG_METHOD); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_IP_PING_ADDRESSES); + return FALSE; + } + if (nm_setting_ip_config_get_may_fail(s_ip4)) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("contains IPv4 address '%s', %s.%s cannot be 'true'"), + address, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP_CONFIG_MAY_FAIL); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_IP_PING_ADDRESSES); + return FALSE; + } + } else { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("contains IPv4 address '%s', %s.%s must be set to 'false' " + "explicitly"), + address, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP_CONFIG_MAY_FAIL); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_IP_PING_ADDRESSES); + return FALSE; + } + } + } else if (addr_family == AF_INET6) { + NMSettingIPConfig *s_ip6; + + if (connection) { + s_ip6 = nm_connection_get_setting_ip6_config(connection); + if (s_ip6) { + const char *method = nm_setting_ip_config_get_method(s_ip6); + if (NM_IN_STRSET(method, + NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_METHOD_DISABLED)) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("contains IPv6 address '%s', %s.%s cannot be '%s'"), + address, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP_CONFIG_METHOD, + method); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_IP_PING_ADDRESSES); + return FALSE; + } + if (nm_setting_ip_config_get_may_fail(s_ip6)) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("contains IPv6 address '%s', %s.%s cannot be 'true'"), + address, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP_CONFIG_MAY_FAIL); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_IP_PING_ADDRESSES); + return FALSE; + } + } else { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("contains IPv6 address '%s', %s.%s must be set to 'false' " + "explicitly"), + address, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP_CONFIG_MAY_FAIL); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_IP_PING_ADDRESSES); + return FALSE; + } + } + } else { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("has an invalid IP address '%s'"), + address); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_IP_PING_ADDRESSES); + return FALSE; + } + } + } + /* *** errors above here should be always fatal, below NORMALIZABLE_ERROR *** */ if (!priv->uuid) { @@ -1711,6 +2053,20 @@ after_interface_name: if (!_nm_setting_connection_verify_secondaries(priv->secondaries.arr, error)) return NM_SETTING_VERIFY_NORMALIZABLE; + if (priv->ip_ping_addresses.arr && priv->ip_ping_addresses.arr->len > 0 + && !_nm_setting_connection_verify_no_duplicate_addresses(priv->ip_ping_addresses.arr, + error)) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("has duplicate addresses")); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_IP_PING_ADDRESSES); + return NM_SETTING_VERIFY_NORMALIZABLE; + } + if (priv->read_only) { g_set_error_literal(error, NM_CONNECTION_ERROR, @@ -2763,6 +3119,70 @@ nm_setting_connection_class_init(NMSettingConnectionClass *klass) secondaries); /** + * NMSettingConnection:ip-ping-addresses: + * + * The property specifies a list of target IP addresses for pinging. + * When multiple targets are set, NetworkManager will start multiple ping processes + * in parallel. This property can only be set if connection.ip-ping-timeout is + * set. The ip-ping-timeout is used to delay the success of IP addressing until + * either the specified timeout (in seconds) is reached, or an target IP address replies + * to a ping. Configuring #NMSettingConnection:ip-ping-addresses may delay reaching the + * systemd's network-online.target due to waiting for the ping operations to complete or timeout. + * + * Since: 1.52 + **/ + _nm_setting_property_define_direct_strv(properties_override, + obj_properties, + NM_SETTING_CONNECTION_IP_PING_ADDRESSES, + PROP_IP_PING_ADDRESSES, + NM_SETTING_PARAM_FUZZY_IGNORE, + NULL, + NMSettingConnectionPrivate, + ip_ping_addresses); + + /** + * NMSettingConnection:ip-ping-addresses-require-all: + * + * The property determines whether it is sufficient for any ping check + * to succeed among #NMSettingConnection:ip-ping-addresses, or if all + * ping checks must succeed for #NMSettingConnection:ip-ping-addresses. + * + * Since: 1.52 + **/ + _nm_setting_property_define_direct_enum(properties_override, + obj_properties, + NM_SETTING_CONNECTION_IP_PING_ADDRESSES_REQUIRE_ALL, + PROP_IP_PING_ADDRESSES_REQUIRE_ALL, + NM_TYPE_TERNARY, + NM_TERNARY_DEFAULT, + NM_SETTING_PARAM_NONE, + NULL, + NMSettingConnectionPrivate, + ip_ping_addresses_require_all); + + /** + * NMSettingConnection:ip-ping-timeout: + * + * If greater than zero, delay success of IP addressing until either the specified + * timeout (in seconds) is reached, or a target IP address replies to a ping. The + * property specifies the timeout for the #NMSettingConnection:ip-ping-addresses. + * This property is incompatible with #NMSettingConnection:gateway-ping-timeout, + * you cannot set these two properties at the same time. + * + * Since: 1.52 + **/ + _nm_setting_property_define_direct_uint32(properties_override, + obj_properties, + NM_SETTING_CONNECTION_IP_PING_TIMEOUT, + PROP_IP_PING_TIMEOUT, + 0, + 600, + 0, + NM_SETTING_PARAM_NONE, + NMSettingConnectionPrivate, + ip_ping_timeout); + + /** * NMSettingConnection:gateway-ping-timeout: * * If greater than zero, delay success of IP addressing until either the diff --git a/src/libnm-core-impl/nm-setting-ethtool.c b/src/libnm-core-impl/nm-setting-ethtool.c index 06c9c12b..9080076c 100644 --- a/src/libnm-core-impl/nm-setting-ethtool.c +++ b/src/libnm-core-impl/nm-setting-ethtool.c @@ -10,6 +10,7 @@ #include "nm-setting-private.h" #include "libnm-base/nm-ethtool-base.h" #include "libnm-base/nm-ethtool-utils-base.h" +#include "libnm-glib-aux/nm-enum-utils.h" /*****************************************************************************/ @@ -121,6 +122,21 @@ nm_ethtool_optname_is_pause(const char *optname) { return optname && nm_ethtool_id_is_pause(nm_ethtool_id_get_by_name(optname)); } +/** + * nm_ethtool_optname_is_fec: + * @optname: (nullable): the option name to check + * + * Checks whether @optname is a valid option name for a fec setting. + * + * Returns: %TRUE, if @optname is valid + * + * Since: 1.52 + */ +gboolean +nm_ethtool_optname_is_fec(const char *optname) +{ + return optname && nm_ethtool_id_is_fec(nm_ethtool_id_get_by_name(optname)); +} /*****************************************************************************/ @@ -309,6 +325,7 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) NMTernary pause_autoneg = NM_TERNARY_DEFAULT; NMTernary pause_tx = NM_TERNARY_DEFAULT; NMTernary pause_rx = NM_TERNARY_DEFAULT; + guint32 fec_mode = 0; len = _nm_setting_option_get_all(setting, &optnames, &variants); @@ -356,6 +373,8 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) pause_rx = g_variant_get_boolean(variant); else if (NM_IN_SET(ethtool_id, NM_ETHTOOL_ID_PAUSE_TX)) pause_tx = g_variant_get_boolean(variant); + else if (NM_IN_SET(ethtool_id, NM_ETHTOOL_ID_FEC_MODE)) + fec_mode = g_variant_get_uint32(variant); } if (pause_rx != NM_TERNARY_DEFAULT || pause_tx != NM_TERNARY_DEFAULT) { @@ -372,6 +391,32 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) } } + if (fec_mode == NM_SETTING_ETHTOOL_FEC_MODE_NONE + || fec_mode >= (_NM_SETTING_ETHTOOL_FEC_MODE_LAST << 1)) { + gs_free const char *cur_fec_mode = NULL; + gs_free const char **valid_all = NULL; + gs_free const char *valid_str = NULL; + + cur_fec_mode = _nm_utils_enum_to_str_full(nm_setting_ethtool_fec_mode_get_type(), + (int) (fec_mode & INT_MAX), + ", ", + NULL); + valid_all = nm_utils_enum_get_values(nm_setting_ethtool_fec_mode_get_type(), 0, G_MAXUINT); + valid_str = g_strjoinv(",", (char **) valid_all); + + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' is not valid FEC modes, valid modes are combinations of %s"), + cur_fec_mode, + valid_str); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_ETHTOOL_SETTING_NAME, + NM_ETHTOOL_OPTNAME_FEC_MODE); + return FALSE; + } + return TRUE; } diff --git a/src/libnm-core-impl/nm-setting-gsm.c b/src/libnm-core-impl/nm-setting-gsm.c index 632b0ccc..02e0e236 100644 --- a/src/libnm-core-impl/nm-setting-gsm.c +++ b/src/libnm-core-impl/nm-setting-gsm.c @@ -38,7 +38,16 @@ NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_AUTO_CONFIG, PROP_SIM_OPERATOR_ID, PROP_MTU, PROP_INITIAL_EPS_CONFIG, - PROP_INITIAL_EPS_APN, ); + PROP_INITIAL_EPS_APN, + PROP_INITIAL_EPS_USERNAME, + PROP_INITIAL_EPS_PASSWORD, + PROP_INITIAL_EPS_PASSWORD_FLAGS, + PROP_INITIAL_EPS_NOAUTH, + PROP_INITIAL_EPS_REFUSE_EAP, + PROP_INITIAL_EPS_REFUSE_PAP, + PROP_INITIAL_EPS_REFUSE_CHAP, + PROP_INITIAL_EPS_REFUSE_MSCHAP, + PROP_INITIAL_EPS_REFUSE_MSCHAPV2, ); typedef struct { char *number; @@ -51,7 +60,16 @@ typedef struct { char *network_id; char *pin; char *initial_eps_apn; + char *initial_eps_username; + char *initial_eps_password; + bool initial_eps_noauth; + bool initial_eps_refuse_eap; + bool initial_eps_refuse_pap; + bool initial_eps_refuse_chap; + bool initial_eps_refuse_mschap; + bool initial_eps_refuse_mschapv2; guint password_flags; + guint initial_eps_password_flags; guint pin_flags; guint32 mtu; bool auto_config; @@ -319,6 +337,134 @@ nm_setting_gsm_get_initial_eps_apn(NMSettingGsm *setting) return NM_SETTING_GSM_GET_PRIVATE(setting)->initial_eps_apn; } +/** + * nm_setting_gsm_get_initial_eps_username: + * @setting: the #NMSettingGsm + * + * Returns: the #NMSettingGsm:initial-eps-bearer-username property of the setting + * + * Since: 1.52 + **/ +const char * +nm_setting_gsm_get_initial_eps_username(NMSettingGsm *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_GSM(setting), NULL); + + return NM_SETTING_GSM_GET_PRIVATE(setting)->initial_eps_username; +} + +/** + * nm_setting_gsm_get_initial_eps_password: + * @setting: the #NMSettingGsm + * + * Returns: the #NMSettingGsm:initial-eps-bearer-password property of the setting + * + * Since: 1.52 + **/ +const char * +nm_setting_gsm_get_initial_eps_password(NMSettingGsm *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_GSM(setting), NULL); + + return NM_SETTING_GSM_GET_PRIVATE(setting)->initial_eps_password; +} + +/** + * nm_setting_gsm_get_initial_eps_noauth: + * @setting: the #NMSettingGsm + * + * Returns: For LTE modems, the #NMSettingGsm:initial-eps-noauth property of the setting + * + * Since: 1.52 + **/ +gboolean +nm_setting_gsm_get_initial_eps_noauth(NMSettingGsm *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_GSM(setting), FALSE); + + return NM_SETTING_GSM_GET_PRIVATE(setting)->initial_eps_noauth; +} + +/** + * nm_setting_gsm_get_initial_eps_refuse_eap: + * @setting: the #NMSettingGsm + * + * Returns: For LTE modems, the #NMSettingGsm:initial-eps-refuse-eap property of the setting + * + * Since: 1.52 + **/ +gboolean +nm_setting_gsm_get_initial_eps_refuse_eap(NMSettingGsm *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_GSM(setting), FALSE); + + return NM_SETTING_GSM_GET_PRIVATE(setting)->initial_eps_refuse_eap; +} + +/** + * nm_setting_gsm_get_initial_eps_refuse_pap: + * @setting: the #NMSettingGsm + * + * Returns: For LTE modems, the #NMSettingGsm:initial-eps-refuse-pap property of the setting + * + * Since: 1.52 + **/ +gboolean +nm_setting_gsm_get_initial_eps_refuse_pap(NMSettingGsm *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_GSM(setting), FALSE); + + return NM_SETTING_GSM_GET_PRIVATE(setting)->initial_eps_refuse_pap; +} + +/** + * nm_setting_gsm_get_initial_eps_refuse_chap: + * @setting: the #NMSettingGsm + * + * Returns: For LTE modems, the #NMSettingGsm:initial-eps-refuse-chap property of the setting + * + * Since: 1.52 + **/ +gboolean +nm_setting_gsm_get_initial_eps_refuse_chap(NMSettingGsm *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_GSM(setting), FALSE); + + return NM_SETTING_GSM_GET_PRIVATE(setting)->initial_eps_refuse_chap; +} + +/** + * nm_setting_gsm_get_initial_eps_refuse_mschap: + * @setting: the #NMSettingGsm + * + * Returns: For LTE modems, the #NMSettingGsm:initial-eps-refuse-mschap property of the setting + * + * Since: 1.52 + **/ +gboolean +nm_setting_gsm_get_initial_eps_refuse_mschap(NMSettingGsm *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_GSM(setting), FALSE); + + return NM_SETTING_GSM_GET_PRIVATE(setting)->initial_eps_refuse_mschap; +} + +/** + * nm_setting_gsm_get_initial_eps_refuse_mschapv2: + * @setting: the #NMSettingGsm + * + * Returns: For LTE modems, the #NMSettingGsm:initial-eps-refuse-mschapv2 property of the setting + * + * Since: 1.52 + **/ +gboolean +nm_setting_gsm_get_initial_eps_refuse_mschapv2(NMSettingGsm *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_GSM(setting), FALSE); + + return NM_SETTING_GSM_GET_PRIVATE(setting)->initial_eps_refuse_mschapv2; +} + static gboolean _verify_apn(const char *apn, gboolean allow_empty, const char *property_name, GError **error) { @@ -847,6 +993,162 @@ nm_setting_gsm_class_init(NMSettingGsmClass *klass) initial_eps_apn, .direct_string_allow_empty = TRUE); + /** + * NMSettingGsm:initial-eps-bearer-username: + * + * For LTE modems, this sets the username for the initial EPS bearer that is set + * up when attaching to the network. Setting this parameter implies + * initial-eps-bearer-configure to be TRUE. + * + * Since: 1.52 + **/ + _nm_setting_property_define_direct_string(properties_override, + obj_properties, + NM_SETTING_GSM_INITIAL_EPS_BEARER_USERNAME, + PROP_INITIAL_EPS_USERNAME, + NM_SETTING_PARAM_NONE, + NMSettingGsmPrivate, + initial_eps_username, + .direct_string_allow_empty = TRUE); + + /** + * NMSettingGsm:initial-eps-bearer-password: + * + * For LTE modems, this sets the password for the initial EPS bearer that is set + * up when attaching to the network. Setting this parameter implies + * initial-eps-bearer-configure to be TRUE. + * + * Since: 1.52 + **/ + _nm_setting_property_define_direct_string(properties_override, + obj_properties, + NM_SETTING_GSM_INITIAL_EPS_BEARER_PASSWORD, + PROP_INITIAL_EPS_PASSWORD, + NM_SETTING_PARAM_SECRET, + NMSettingGsmPrivate, + initial_eps_password, + .direct_string_allow_empty = TRUE); + + /** + * NMSettingGsm:initial-eps-bearer-password-flags: + * + * Flags indicating how to handle the #NMSettingGsm:initial-eps-bearer-password property. + * + * Since: 1.52 + **/ + _nm_setting_property_define_direct_secret_flags( + properties_override, + obj_properties, + NM_SETTING_GSM_INITIAL_EPS_BEARER_PASSWORD_FLAGS, + PROP_INITIAL_EPS_PASSWORD_FLAGS, + NMSettingGsmPrivate, + initial_eps_password_flags); + + /** + * NMSettingGsm:initial-eps-bearer-noauth: + * + * For LTE modems, this sets NOAUTH authentication method for the initial EPS bearer that is set + * up when attaching to the network. + * If %TRUE, do not require the other side to authenticate itself to the client. + * If %FALSE, require authentication from the remote side. In almost all cases, + * this should be %TRUE. + * + * Since: 1.52 + **/ + _nm_setting_property_define_direct_boolean(properties_override, + obj_properties, + NM_SETTING_GSM_INITIAL_EPS_BEARER_NOAUTH, + PROP_INITIAL_EPS_NOAUTH, + TRUE, + NM_SETTING_PARAM_NONE, + NMSettingGsmPrivate, + initial_eps_noauth); + + /** + * NMSettingGsm:initial-eps-bearer-refuse-eap: + * + * For LTE modems, this disables EAP authentication method for the initial EPS bearer that is set + * up when attaching to the network. + * + * Since: 1.52 + **/ + _nm_setting_property_define_direct_boolean(properties_override, + obj_properties, + NM_SETTING_GSM_INITIAL_EPS_BEARER_REFUSE_EAP, + PROP_INITIAL_EPS_REFUSE_EAP, + FALSE, + NM_SETTING_PARAM_NONE, + NMSettingGsmPrivate, + initial_eps_refuse_eap); + + /** + * NMSettingGsm:initial-eps-bearer-refuse-pap: + * + * For LTE modems, this disables PAP authentication method for the initial EPS bearer that is set + * up when attaching to the network. + * + * Since: 1.52 + **/ + _nm_setting_property_define_direct_boolean(properties_override, + obj_properties, + NM_SETTING_GSM_INITIAL_EPS_BEARER_REFUSE_PAP, + PROP_INITIAL_EPS_REFUSE_PAP, + FALSE, + NM_SETTING_PARAM_NONE, + NMSettingGsmPrivate, + initial_eps_refuse_pap); + + /** + * NMSettingGsm:initial-eps-bearer-refuse-chap: + * + * For LTE modems, this disables CHAP authentication method for the initial EPS bearer that is set + * up when attaching to the network. + * + * Since: 1.52 + **/ + _nm_setting_property_define_direct_boolean(properties_override, + obj_properties, + NM_SETTING_GSM_INITIAL_EPS_BEARER_REFUSE_CHAP, + PROP_INITIAL_EPS_REFUSE_CHAP, + FALSE, + NM_SETTING_PARAM_NONE, + NMSettingGsmPrivate, + initial_eps_refuse_chap); + + /** + * NMSettingGsm:initial-eps-bearer-refuse-mschap: + * + * For LTE modems, this disables MSCHAP authentication method for the initial EPS bearer that is set + * up when attaching to the network. + * + * Since: 1.52 + **/ + _nm_setting_property_define_direct_boolean(properties_override, + obj_properties, + NM_SETTING_GSM_INITIAL_EPS_BEARER_REFUSE_MSCHAP, + PROP_INITIAL_EPS_REFUSE_MSCHAP, + FALSE, + NM_SETTING_PARAM_NONE, + NMSettingGsmPrivate, + initial_eps_refuse_mschap); + + /** + * NMSettingGsm:initial-eps-bearer-refuse-mschapv2: + * + * For LTE modems, this disables MSCHAPV2 authentication method for the initial EPS bearer that is set + * up when attaching to the network. + * + * Since: 1.52 + **/ + _nm_setting_property_define_direct_boolean(properties_override, + obj_properties, + NM_SETTING_GSM_INITIAL_EPS_BEARER_REFUSE_MSCHAPV2, + PROP_INITIAL_EPS_REFUSE_MSCHAPV2, + FALSE, + NM_SETTING_PARAM_NONE, + NMSettingGsmPrivate, + initial_eps_refuse_mschapv2); + /* Ignore incoming deprecated properties */ _nm_properties_override_dbus(properties_override, "allowed-bands", diff --git a/src/libnm-core-impl/nm-setting-ip-config.c b/src/libnm-core-impl/nm-setting-ip-config.c index e79f25a8..1ec97029 100644 --- a/src/libnm-core-impl/nm-setting-ip-config.c +++ b/src/libnm-core-impl/nm-setting-ip-config.c @@ -175,7 +175,7 @@ nm_ip_address_new(int family, const char *addr, guint prefix, GError **error) return NULL; address = g_slice_new(NMIPAddress); - *address = (NMIPAddress){ + *address = (NMIPAddress) { .refcount = 1, .family = family, .address = canonicalize_ip_binary(family, &addr_bin, FALSE), @@ -210,7 +210,7 @@ nm_ip_address_new_binary(int family, gconstpointer addr, guint prefix, GError ** return NULL; address = g_slice_new(NMIPAddress); - *address = (NMIPAddress){ + *address = (NMIPAddress) { .refcount = 1, .family = family, .address = nm_inet_ntop_dup(family, addr), @@ -637,7 +637,7 @@ nm_ip_route_new(int family, return NULL; route = g_slice_new(NMIPRoute); - *route = (NMIPRoute){ + *route = (NMIPRoute) { .refcount = 1, .family = family, .dest = canonicalize_ip_binary(family, &dest_bin, FALSE), @@ -683,7 +683,7 @@ nm_ip_route_new_binary(int family, return NULL; route = g_slice_new0(NMIPRoute); - *route = (NMIPRoute){ + *route = (NMIPRoute) { .refcount = 1, .family = family, .dest = canonicalize_ip_binary(family, dest, FALSE), @@ -1655,7 +1655,7 @@ nm_ip_routing_rule_new(int addr_family) g_return_val_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6), NULL); self = g_slice_new(NMIPRoutingRule); - *self = (NMIPRoutingRule){ + *self = (NMIPRoutingRule) { .ref_count = 1, .is_v4 = (addr_family == AF_INET), .action = FR_ACT_TO_TBL, @@ -1685,7 +1685,7 @@ nm_ip_routing_rule_new_clone(const NMIPRoutingRule *rule) g_return_val_if_fail(NM_IS_IP_ROUTING_RULE(rule, TRUE), NULL); self = g_slice_new(NMIPRoutingRule); - *self = (NMIPRoutingRule){ + *self = (NMIPRoutingRule) { .ref_count = 1, .sealed = FALSE, .is_v4 = rule->is_v4, @@ -3996,6 +3996,7 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMSettingIPConfig, PROP_DHCP_DSCP, PROP_DHCP_HOSTNAME_FLAGS, PROP_DHCP_SEND_HOSTNAME, + PROP_DHCP_SEND_HOSTNAME_V2, PROP_NEVER_DEFAULT, PROP_MAY_FAIL, PROP_DAD_TIMEOUT, @@ -4005,7 +4006,10 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMSettingIPConfig, PROP_DHCP_REJECT_SERVERS, PROP_AUTO_ROUTE_EXT_GW, PROP_REPLACE_LOCAL_RULE, - PROP_DHCP_SEND_RELEASE, ); + PROP_DHCP_SEND_RELEASE, + PROP_ROUTED_DNS, + PROP_SHARED_DHCP_RANGE, + PROP_SHARED_DHCP_LEASE_TIME, ); G_DEFINE_ABSTRACT_TYPE(NMSettingIPConfig, nm_setting_ip_config, NM_TYPE_SETTING) @@ -4091,7 +4095,7 @@ _ip_config_add_dns(NMSettingIPConfig *setting, const char *dns) priv = NM_SETTING_IP_CONFIG_GET_PRIVATE(setting); - s = nm_utils_dnsname_normalize(NM_SETTING_IP_CONFIG_GET_ADDR_FAMILY(setting), dns, &s_free); + s = nm_dns_uri_normalize(NM_SETTING_IP_CONFIG_GET_ADDR_FAMILY(setting), dns, &s_free); if (!s) s = dns; @@ -4182,7 +4186,7 @@ nm_setting_ip_config_remove_dns_by_value(NMSettingIPConfig *setting, const char gs_free char *s_free = NULL; const char *s; - s = nm_utils_dnsname_normalize(NM_SETTING_IP_CONFIG_GET_ADDR_FAMILY(setting), dns, &s_free); + s = nm_dns_uri_normalize(NM_SETTING_IP_CONFIG_GET_ADDR_FAMILY(setting), dns, &s_free); if (s && !nm_streq(dns, s)) idx = nm_strv_ptrarray_find_first(priv->dns, dns); } @@ -5193,6 +5197,8 @@ nm_setting_ip_config_get_dhcp_hostname(NMSettingIPConfig *setting) * Returns: %TRUE if NetworkManager should send the machine hostname to the * DHCP server when requesting addresses to allow the server to automatically * update DNS information for this machine. + * + * Deprecated: 1.52. Use nm_setting_ip_config_get_dhcp_send_hostname_v2() instead. **/ gboolean nm_setting_ip_config_get_dhcp_send_hostname(NMSettingIPConfig *setting) @@ -5203,6 +5209,25 @@ nm_setting_ip_config_get_dhcp_send_hostname(NMSettingIPConfig *setting) } /** + * nm_setting_ip_config_get_dhcp_send_hostname_v2: + * @setting: the #NMSettingIPConfig + * + * Returns the value contained in the #NMSettingIPConfig:dhcp-send-hostname-v2 + * property. + * + * Returns: the #NMSettingIPConfig:dhcp-send-hostname-v2 property of the setting + * + * Since: 1.52 + **/ +NMTernary +nm_setting_ip_config_get_dhcp_send_hostname_v2(NMSettingIPConfig *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_IP_CONFIG(setting), NM_TERNARY_DEFAULT); + + return NM_SETTING_IP_CONFIG_GET_PRIVATE(setting)->dhcp_send_hostname_v2; +} + +/** * nm_setting_ip_config_get_dhcp_dscp: * @setting: the #NMSettingIPConfig * @@ -5480,6 +5505,60 @@ nm_setting_ip_config_get_dhcp_send_release(NMSettingIPConfig *setting) return NM_SETTING_IP_CONFIG_GET_PRIVATE(setting)->dhcp_send_release; } +/** + * nm_setting_ip_config_get_routed_dns: + * @setting: the #NMSettingIPConfig + * + * Returns: the #NMSettingIPConfig:routed-dns property of the setting + * + * Since: 1.52 + **/ +NMSettingIPConfigRoutedDns +nm_setting_ip_config_get_routed_dns(NMSettingIPConfig *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_IP_CONFIG(setting), NM_SETTING_IP_CONFIG_ROUTED_DNS_DEFAULT); + + return NM_SETTING_IP_CONFIG_GET_PRIVATE(setting)->routed_dns; +} + +/** + * nm_setting_ip_config_get_shared_dhcp_range: + * @setting: the #NMSettingIPConfig + * + * Returns the value contained in the #NMSettingIPConfig:shared-dhcp-range + * property. + * + * Returns: the configured DHCP server range + * + * Since: 1.52 + **/ +const char * +nm_setting_ip_config_get_shared_dhcp_range(NMSettingIPConfig *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_IP_CONFIG(setting), NULL); + + return NM_SETTING_IP_CONFIG_GET_PRIVATE(setting)->shared_dhcp_range; +} + +/** + * nm_setting_ip_config_get_shared_dhcp_lease_time: + * @setting: the #NMSettingIPConfig + * + * Returns the value contained in the #NMSettingIPConfig:shared-dhcp-lease-time + * property. + * + * Returns: the configured DHCP server lease time + * + * Since: 1.52 + **/ +int +nm_setting_ip_config_get_shared_dhcp_lease_time(NMSettingIPConfig *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_IP_CONFIG(setting), 0); + + return NM_SETTING_IP_CONFIG_GET_PRIVATE(setting)->shared_dhcp_lease_time; +} + static gboolean verify_label(const char *label) { @@ -5536,11 +5615,7 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) for (i = 0; i < priv->dns->len; i++) { const char *dns = priv->dns->pdata[i]; - if (!nm_utils_dnsname_parse(NM_SETTING_IP_CONFIG_GET_ADDR_FAMILY(setting), - dns, - NULL, - NULL, - NULL)) { + if (!nm_dns_uri_parse(NM_SETTING_IP_CONFIG_GET_ADDR_FAMILY(setting), dns, NULL)) { g_set_error(error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, @@ -5776,6 +5851,26 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) return FALSE; } + /* Validate DHCP range served in the shared mode */ + if (priv->shared_dhcp_range + && !nm_utils_validate_shared_dhcp_range(priv->shared_dhcp_range, priv->addresses, error)) { + g_prefix_error(error, + "%s.%s: ", + nm_setting_get_name(setting), + NM_SETTING_IP_CONFIG_SHARED_DHCP_RANGE); + return FALSE; + } + + /* Validate DHCP lease time */ + if (priv->shared_dhcp_lease_time + && !nm_utils_validate_shared_dhcp_lease_time(priv->shared_dhcp_lease_time, error)) { + g_prefix_error(error, + "%s.%s: ", + nm_setting_get_name(setting), + NM_SETTING_IP_CONFIG_SHARED_DHCP_LEASE_TIME); + return FALSE; + } + /* Normalizable errors */ if (priv->gateway && priv->never_default) { g_set_error(error, @@ -5790,6 +5885,20 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) return NM_SETTING_VERIFY_NORMALIZABLE_ERROR; } + if (priv->dhcp_send_hostname_v2 != NM_TERNARY_DEFAULT + && priv->dhcp_send_hostname != priv->dhcp_send_hostname_v2) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("the value is inconsistent with '%s'"), + NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME_V2); + g_prefix_error(error, + "%s.%s: ", + nm_setting_get_name(setting), + NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME); + return NM_SETTING_VERIFY_NORMALIZABLE_ERROR; + } + return TRUE; } @@ -6133,6 +6242,14 @@ _nm_sett_info_property_override_create_array_ip_config(int addr_family) _nm_properties_override_gobj( properties_override, + obj_properties[PROP_DHCP_SEND_HOSTNAME_V2], + &nm_sett_info_propert_type_direct_enum, + .direct_offset = + NM_STRUCT_OFFSET_ENSURE_TYPE(int, NMSettingIPConfigPrivate, dhcp_send_hostname_v2), + .direct_data.enum_gtype = NM_TYPE_TERNARY); + + _nm_properties_override_gobj( + properties_override, obj_properties[PROP_DHCP_HOSTNAME_FLAGS], &nm_sett_info_propert_type_direct_uint32, .direct_offset = @@ -6198,6 +6315,28 @@ _nm_sett_info_property_override_create_array_ip_config(int addr_family) NMSettingIPConfigPrivate, dhcp_reject_servers)); + _nm_properties_override_gobj( + properties_override, + obj_properties[PROP_ROUTED_DNS], + &nm_sett_info_propert_type_direct_enum, + .direct_offset = NM_STRUCT_OFFSET_ENSURE_TYPE(int, NMSettingIPConfigPrivate, routed_dns), + .direct_data.enum_gtype = NM_TYPE_SETTING_IP_CONFIG_ROUTED_DNS); + + _nm_properties_override_gobj( + properties_override, + obj_properties[PROP_SHARED_DHCP_RANGE], + &nm_sett_info_propert_type_direct_string, + .direct_offset = + NM_STRUCT_OFFSET_ENSURE_TYPE(char *, NMSettingIPConfigPrivate, shared_dhcp_range), + .direct_string_allow_empty = TRUE); + + _nm_properties_override_gobj( + properties_override, + obj_properties[PROP_SHARED_DHCP_LEASE_TIME], + &nm_sett_info_propert_type_direct_int32, + .direct_offset = + NM_STRUCT_OFFSET_ENSURE_TYPE(gint32, NMSettingIPConfigPrivate, shared_dhcp_lease_time)); + return properties_override; } @@ -6367,11 +6506,16 @@ nm_setting_ip_config_class_init(NMSettingIPConfigClass *klass) /** * NMSettingIPConfig:dns: * - * Array of IP addresses of DNS servers. + * Array of DNS servers. + * + * Each server can be specified either as a plain IP address (optionally followed + * by a "#" and the SNI server name for DNS over TLS) or with a URI syntax. + * + * When it is specified as an URI, the following forms are supported: + * dns+udp://ADDRESS[:PORT], dns+tls://ADDRESS[:PORT][#SERVERNAME] . * - * For DoT (DNS over TLS), the SNI server name can be specified by appending - * "#example.com" to the IP address of the DNS server. This currently only has - * effect when using systemd-resolved. + * When using the URI syntax, IPv6 addresses must be enclosed in square + * brackets ('[', ']'). **/ obj_properties[PROP_DNS] = g_param_spec_boxed(NM_SETTING_IP_CONFIG_DNS, @@ -6662,12 +6806,21 @@ nm_setting_ip_config_class_init(NMSettingIPConfigClass *klass) /** * NMSettingIPConfig:dhcp-send-hostname: * - * If %TRUE, a hostname is sent to the DHCP server when acquiring a lease. - * Some DHCP servers use this hostname to update DNS databases, essentially - * providing a static hostname for the computer. If the - * #NMSettingIPConfig:dhcp-hostname property is %NULL and this property is - * %TRUE, the current persistent hostname of the computer is sent. + * Since 1.52 this property is deprecated and is only used as fallback value + * for #NMSettingIPConfig:dhcp-send-hostname-v2 if it's set to 'default'. + * This is only done to avoid breaking existing configurations, the new + * property should be used from now on. + * + * Deprecated: 1.52: use the new version of dhcp-send-hostname instead. **/ + /* ---nmcli--- + * property: dhcp-send-hostname + * rename: dhcp-send-hostname-deprecated + * description: Since 1.52 this property is deprecated and is only used as fallback value + * for dhcp-send-hostname if it's set to 'default'. This is only done to avoid + * breaking existing configurations, the new property should be used from now on. + * ---end--- + */ obj_properties[PROP_DHCP_SEND_HOSTNAME] = g_param_spec_boolean(NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME, "", @@ -6946,5 +7099,111 @@ nm_setting_ip_config_class_init(NMSettingIPConfigClass *klass) NM_TERNARY_DEFAULT, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + /** + * NMSettingIPConfig:routed-dns: + * + * Whether to add routes for DNS servers. When enabled, NetworkManager adds a route + * for each DNS server that is associated with this connection either statically + * (defined in the connection profile) or dynamically (for example, retrieved via + * DHCP). The route guarantees that the DNS server is reached via this interface. When + * set to %NM_SETTING_IP_CONFIG_ROUTED_DNS_DEFAULT, the value from global + * configuration is used; if no global default is defined, this feature is disabled. + * + * Since: 1.52 + */ + obj_properties[PROP_ROUTED_DNS] = + g_param_spec_int(NM_SETTING_IP_CONFIG_ROUTED_DNS, + "", + "", + NM_SETTING_IP_CONFIG_ROUTED_DNS_DEFAULT, + NM_SETTING_IP_CONFIG_ROUTED_DNS_YES, + NM_SETTING_IP_CONFIG_ROUTED_DNS_DEFAULT, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + /** + * NMSettingIPConfig:dhcp-send-hostname-v2: + * + * If %TRUE, a hostname is sent to the DHCP server when acquiring a lease. + * Some DHCP servers use this hostname to update DNS databases, essentially + * providing a static hostname for the computer. If the + * #NMSettingIPConfig:dhcp-hostname property is %NULL and this property is + * %TRUE, the current persistent hostname of the computer is sent. + * + * The default value is %NM_TERNARY_DEFAULT. In this case the global value + * from NetworkManager configuration is looked up. If it's not set, the value + * from #NMSettingIPConfig:dhcp-send-hostname, which defaults to %TRUE, is + * used for backwards compatibility. In the future this will change and, in + * absence of a global default, it will always fallback to %TRUE. + * + * Since: 1.52 + **/ + /* ---nmcli--- + * property: dhcp-send-hostname-v2 + * rename: dhcp-send-hostname + * description: If %TRUE, a hostname is sent to the DHCP server when acquiring a lease. + * Some DHCP servers use this hostname to update DNS databases, essentially + * providing a static hostname for the computer. If the dhcp-hostname + * property is %NULL and this property is %TRUE, the current persistent + * hostname of the computer is sent. + * + * The default value is %NM_TERNARY_DEFAULT. In this case the global value + * from NetworkManager configuration is looked up. If it's not set, the value + * from dhcp-send-hostname-deprecated, which defaults to %TRUE, is + * used for backwards compatibility. In the future this will change and, in + * absence of a global default, it will always fallback to %TRUE. + * ---end--- + */ + obj_properties[PROP_DHCP_SEND_HOSTNAME_V2] = + g_param_spec_int(NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME_V2, + "", + "", + G_MININT, + G_MAXINT, + NM_TERNARY_DEFAULT, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + /** + * NMSettingIPConfig:shared-dhcp-range: + * + * This option allows you to specify a custom DHCP range for the shared connection + * method. The value is expected to be in `<START_ADDRESS>,<END_ADDRESS>` format. + * The range should be part of network set by ipv4.address option and it should + * not contain network address or broadcast address. If this option is not specified, + * the DHCP range will be automatically determined based on the interface address. + * The range will be selected to be adjacent to the interface address, either before + * or after it, with the larger possible range being preferred. The range will be + * adjusted to fill the available address space, except for networks with a prefix + * length greater than 24, which will be treated as if they have a prefix length of 24. + * + * Since: 1.52 + */ + obj_properties[PROP_SHARED_DHCP_RANGE] = + g_param_spec_string(NM_SETTING_IP_CONFIG_SHARED_DHCP_RANGE, + "", + "", + NULL, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + /** + * NMSettingIPConfig:shared-dhcp-lease-time: + * + * This option allows you to specify a custom DHCP lease time for the shared connection + * method in seconds. The value should be either a number between 120 and 31536000 (one year) + * If this option is not specified, 3600 (one hour) is used. + * + * Special values are 0 for default value of 1 hour and 2147483647 (MAXINT32) for infinite lease time. + * + * Since: 1.52 + */ + obj_properties[PROP_SHARED_DHCP_LEASE_TIME] = + g_param_spec_int(NM_SETTING_IP_CONFIG_SHARED_DHCP_LEASE_TIME, + "", + "", + 0, + G_MAXINT32, + 0, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | NM_SETTING_PARAM_FUZZY_IGNORE + | G_PARAM_STATIC_STRINGS); + g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); } diff --git a/src/libnm-core-impl/nm-setting-ip4-config.c b/src/libnm-core-impl/nm-setting-ip4-config.c index 6112137f..a4fccc6d 100644 --- a/src/libnm-core-impl/nm-setting-ip4-config.c +++ b/src/libnm-core-impl/nm-setting-ip4-config.c @@ -39,7 +39,8 @@ NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_DHCP_CLIENT_ID, PROP_DHCP_FQDN, PROP_DHCP_VENDOR_CLASS_IDENTIFIER, - PROP_LINK_LOCAL, ); + PROP_LINK_LOCAL, + PROP_DHCP_IPV6_ONLY_PREFERRED, ); typedef struct { NMSettingIPConfigPrivate parent; @@ -48,6 +49,7 @@ typedef struct { char *dhcp_fqdn; char *dhcp_vendor_class_identifier; gint32 link_local; + gint32 dhcp_ipv6_only_preferred; } NMSettingIP4ConfigPrivate; /** @@ -146,6 +148,26 @@ nm_setting_ip4_config_get_link_local(NMSettingIP4Config *setting) return NM_SETTING_IP4_CONFIG_GET_PRIVATE(setting)->link_local; } +/** + * nm_setting_ip4_config_get_dhcp_ipv6_only_preferred: + * @setting: the #NMSettingIP4Config + * + * Returns the value in the #NMSettingIP4Config:dhcp-ipv6-only-preferred + * property. + * + * Returns: the DHCP IPv6-only preferred property value + * + * Since: 1.52 + **/ +NMSettingIP4DhcpIpv6OnlyPreferred +nm_setting_ip4_config_get_dhcp_ipv6_only_preferred(NMSettingIP4Config *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_IP4_CONFIG(setting), + NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_DEFAULT); + + return NM_SETTING_IP4_CONFIG_GET_PRIVATE(setting)->dhcp_ipv6_only_preferred; +} + static gboolean verify(NMSetting *setting, NMConnection *connection, GError **error) { @@ -241,7 +263,8 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) NM_SETTING_IP4_LL_AUTO, NM_SETTING_IP4_LL_DEFAULT, NM_SETTING_IP4_LL_DISABLED, - NM_SETTING_IP4_LL_ENABLED)) { + NM_SETTING_IP4_LL_ENABLED, + NM_SETTING_IP4_LL_FALLBACK)) { g_set_error(error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, @@ -252,7 +275,7 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) NM_SETTING_IP4_CONFIG_LINK_LOCAL); return FALSE; } - if (priv->link_local == NM_SETTING_IP4_LL_ENABLED + if (NM_IN_SET(priv->link_local, NM_SETTING_IP4_LL_ENABLED, NM_SETTING_IP4_LL_FALLBACK) && nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) { g_set_error_literal(error, NM_CONNECTION_ERROR, @@ -1028,6 +1051,8 @@ nm_setting_ip4_config_class_init(NMSettingIP4ConfigClass *klass) * When set to "default", it honors the global connection default, before * falling back to "auto". Note that if "ipv4.method" is "disabled", then * link local addressing is always disabled too. The default is "default". + * Since 1.52, when set to "fallback", a link-local address is obtained + * if no other IPv4 address is set. * * Since: 1.40 */ @@ -1325,6 +1350,38 @@ nm_setting_ip4_config_class_init(NMSettingIP4ConfigClass *klass) * ---end--- */ + /** + * NMSettingIP4Config:dhcp-ipv6-only-preferred + * + * Controls the "IPv6-Only Preferred" DHCPv4 option (RFC 8925). + * + * When set to %NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_YES, the host adds the + * option to the parameter request list; if the DHCP server sends the option back, + * the host stops the DHCP client for the time interval specified in the option. + * + * Enable this feature if the host supports an IPv6-only mode, i.e. either all + * applications are IPv6-only capable or there is a form of 464XLAT deployed. + * + * When set to %NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_DEFAULT, the actual value + * is looked up in the global configuration; if not specified, it defaults to + * %NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_NO. + * + * If the connection has IPv6 method set to "disabled", this property does not + * have effect and the "IPv6-Only Preferred" option is always disabled. + * + * Since: 1.52 + */ + _nm_setting_property_define_direct_enum(properties_override, + obj_properties, + NM_SETTING_IP4_CONFIG_DHCP_IPV6_ONLY_PREFERRED, + PROP_DHCP_IPV6_ONLY_PREFERRED, + NM_TYPE_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED, + NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_DEFAULT, + NM_SETTING_PARAM_NONE, + NULL, + NMSettingIP4ConfigPrivate, + dhcp_ipv6_only_preferred); + g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); _nm_setting_class_commit(setting_class, diff --git a/src/libnm-core-impl/nm-setting-ip6-config.c b/src/libnm-core-impl/nm-setting-ip6-config.c index 32fb295f..c68be991 100644 --- a/src/libnm-core-impl/nm-setting-ip6-config.c +++ b/src/libnm-core-impl/nm-setting-ip6-config.c @@ -440,6 +440,30 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) return FALSE; } + if (nm_setting_ip_config_get_shared_dhcp_range(s_ip)) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("Shared DHCP range is not supported for IPv6")); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP_CONFIG_SHARED_DHCP_RANGE); + return FALSE; + } + + if (nm_setting_ip_config_get_shared_dhcp_lease_time(s_ip)) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("Shared DHCP lease time is not supported for IPv6")); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP_CONFIG_SHARED_DHCP_LEASE_TIME); + return FALSE; + } + /* Failures from here on, are NORMALIZABLE_ERROR... */ if (token_needs_normalization) { diff --git a/src/libnm-core-impl/nm-setting-ipvlan.c b/src/libnm-core-impl/nm-setting-ipvlan.c new file mode 100644 index 00000000..fafa37b6 --- /dev/null +++ b/src/libnm-core-impl/nm-setting-ipvlan.c @@ -0,0 +1,290 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024 Red Hat, Inc. + */ + +#include "libnm-core-impl/nm-default-libnm-core.h" + +#include "nm-setting-ipvlan.h" + +#include "nm-connection-private.h" +#include "nm-utils.h" +#include "nm-utils-private.h" + +/** + * SECTION:nm-setting-ipvlan + * @short_description: Describes connection properties for IPVLAN interfaces + * + * The #NMSettingIpvlan object is a #NMSetting subclass that describes properties + * necessary for connection to IPVLAN interfaces. + **/ + +/*****************************************************************************/ + +NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_PARENT, PROP_MODE, PROP_PRIVATE, PROP_VEPA, ); + +typedef struct { + char *parent; + guint32 mode; + bool private_flag; + bool vepa; +} NMSettingIpvlanPrivate; + +/** + * NMSettingIpvlan: + * + * IPVLAN Settings + */ +struct _NMSettingIpvlan { + NMSetting parent; + NMSettingIpvlanPrivate _priv; +}; + +struct _NMSettingIpvlanClass { + NMSettingClass parent; +}; + +G_DEFINE_TYPE(NMSettingIpvlan, nm_setting_ipvlan, NM_TYPE_SETTING) + +#define NM_SETTING_IPVLAN_GET_PRIVATE(o) \ + _NM_GET_PRIVATE(o, NMSettingIpvlan, NM_IS_SETTING_IPVLAN, NMSetting) + +/*****************************************************************************/ + +/** + * nm_setting_ipvlan_get_parent: + * @setting: the #NMSettingIpvlan + * + * Returns: the #NMSettingIpvlan:parent property of the setting + * + * Since: 1.52 + **/ +const char * +nm_setting_ipvlan_get_parent(NMSettingIpvlan *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_IPVLAN(setting), NULL); + + return NM_SETTING_IPVLAN_GET_PRIVATE(setting)->parent; +} + +/** + * nm_setting_ipvlan_get_mode: + * @setting: the #NMSettingIpvlan + * + * Returns: the #NMSettingIpvlan:mode property of the setting + * + * Since: 1.52 + **/ +NMSettingIpvlanMode +nm_setting_ipvlan_get_mode(NMSettingIpvlan *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_IPVLAN(setting), NM_SETTING_IPVLAN_MODE_UNKNOWN); + + return NM_SETTING_IPVLAN_GET_PRIVATE(setting)->mode; +} + +/** + * nm_setting_ipvlan_get_private: + * @setting: the #NMSettingIpvlan + * + * Returns: the #NMSettingIpvlan:private property of the setting + * + * Since: 1.52 + **/ +gboolean +nm_setting_ipvlan_get_private(NMSettingIpvlan *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_IPVLAN(setting), FALSE); + + return NM_SETTING_IPVLAN_GET_PRIVATE(setting)->private_flag; +} + +/** + * nm_setting_ipvlan_get_vepa: + * @setting: the #NMSettingIpvlan + * + * Returns: the #NMSettingIpvlan:vepa property of the setting + * + * Since: 1.52 + **/ +gboolean +nm_setting_ipvlan_get_vepa(NMSettingIpvlan *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_IPVLAN(setting), FALSE); + + return NM_SETTING_IPVLAN_GET_PRIVATE(setting)->vepa; +} + +/*****************************************************************************/ + +static gboolean +verify(NMSetting *setting, NMConnection *connection, GError **error) +{ + NMSettingIpvlanPrivate *priv = NM_SETTING_IPVLAN_GET_PRIVATE(setting); + NMSettingWired *s_wired = NULL; + + if (connection) + s_wired = nm_connection_get_setting_wired(connection); + + if (priv->parent) { + if (!nm_utils_is_uuid(priv->parent) && !nm_utils_ifname_valid_kernel(priv->parent, NULL)) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' is neither an UUID nor an interface name"), + priv->parent); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_IPVLAN_SETTING_NAME, + NM_SETTING_IPVLAN_PARENT); + return FALSE; + } + } else { + /* If parent is NULL, the parent must be specified via NMSettingWired:mac-address. */ + if (connection && (!s_wired || !nm_setting_wired_get_mac_address(s_wired))) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_MISSING_PROPERTY, + _("property is not specified and neither is '%s:%s'"), + NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_WIRED_MAC_ADDRESS); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_IPVLAN_SETTING_NAME, + NM_SETTING_IPVLAN_PARENT); + return FALSE; + } + } + + if (priv->private_flag && priv->vepa) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("private and VEPA cannot be enabled at the same time")); + g_prefix_error(error, "%s: ", NM_SETTING_IPVLAN_SETTING_NAME); + return FALSE; + } + + if (!_nm_connection_verify_required_interface_name(connection, error)) + return FALSE; + + return TRUE; +} + +/*****************************************************************************/ + +static void +nm_setting_ipvlan_init(NMSettingIpvlan *self) +{} + +/** + * nm_setting_ipvlan_new: + * + * Creates a new #NMSettingIpvlan object with default values. + * + * Returns: (transfer full): the new empty #NMSettingIpvlan object + * + * Since: 1.52 + **/ +NMSetting * +nm_setting_ipvlan_new(void) +{ + return g_object_new(NM_TYPE_SETTING_IPVLAN, NULL); +} + +static void +nm_setting_ipvlan_class_init(NMSettingIpvlanClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + NMSettingClass *setting_class = NM_SETTING_CLASS(klass); + GArray *properties_override = _nm_sett_info_property_override_create_array(); + + object_class->get_property = _nm_setting_property_get_property_direct; + object_class->set_property = _nm_setting_property_set_property_direct; + + setting_class->verify = verify; + + /** + * NMSettingIpvlan:parent: + * + * If given, specifies the parent interface name or parent connection UUID + * from which this IPVLAN interface should be created. If this property is + * not specified, the connection must contain an #NMSettingWired setting + * with a #NMSettingWired:mac-address property. + * + * Since: 1.52 + **/ + _nm_setting_property_define_direct_string(properties_override, + obj_properties, + NM_SETTING_IPVLAN_PARENT, + PROP_PARENT, + NM_SETTING_PARAM_INFERRABLE, + NMSettingIpvlanPrivate, + parent, + .direct_string_allow_empty = TRUE); + + /** + * NMSettingIpvlan:mode: + * + * The IPVLAN mode. Valid values: %NM_SETTING_IPVLAN_MODE_L2, + * %NM_SETTING_IPVLAN_MODE_L3 and %NM_SETTING_IPVLAN_MODE_L3S. + * + * Since: 1.52 + **/ + /* ---nmcli--- + * property: mode + * description: + * The IPVLAN mode. Valid values: l2 (1), l3 (2), l3s (3) + * ---end--- + */ + _nm_setting_property_define_direct_uint32(properties_override, + obj_properties, + NM_SETTING_IPVLAN_MODE, + PROP_MODE, + 0, + G_MAXUINT32, + NM_SETTING_IPVLAN_MODE_UNKNOWN, + NM_SETTING_PARAM_INFERRABLE, + NMSettingIpvlanPrivate, + mode); + + /** + * NMSettingIpvlan:private: + * + * Whether the interface should be put in private mode. + * + * Since: 1.52 + **/ + _nm_setting_property_define_direct_boolean(properties_override, + obj_properties, + NM_SETTING_IPVLAN_PRIVATE, + PROP_PRIVATE, + FALSE, + NM_SETTING_PARAM_INFERRABLE, + NMSettingIpvlanPrivate, + private_flag); + + /** + * NMSettingIpvlan:vepa: + * + * Whether the interface should be put in VEPA mode. + * + * Since: 1.52 + **/ + _nm_setting_property_define_direct_boolean(properties_override, + obj_properties, + NM_SETTING_IPVLAN_VEPA, + PROP_VEPA, + FALSE, + NM_SETTING_PARAM_INFERRABLE, + NMSettingIpvlanPrivate, + vepa); + + g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + _nm_setting_class_commit(setting_class, + NM_META_SETTING_TYPE_IPVLAN, + NULL, + properties_override, + G_STRUCT_OFFSET(NMSettingIpvlan, _priv)); +} diff --git a/src/libnm-core-impl/nm-setting-private.h b/src/libnm-core-impl/nm-setting-private.h index da7fdbb7..ba838364 100644 --- a/src/libnm-core-impl/nm-setting-private.h +++ b/src/libnm-core-impl/nm-setting-private.h @@ -186,10 +186,14 @@ typedef struct { char *dhcp_hostname; char *dhcp_iaid; char *dhcp_dscp; + char *shared_dhcp_range; + int shared_dhcp_lease_time; gint64 route_metric; int auto_route_ext_gw; int replace_local_rule; int dhcp_send_release; + int routed_dns; + int dhcp_send_hostname_v2; gint32 required_timeout; gint32 dad_timeout; gint32 dhcp_timeout; @@ -482,7 +486,7 @@ void _nm_setting_class_commit(NMSettingClass *setting_class, &_g; \ }) -#define NM_SETT_INFO_SETT_DETAIL(...) (&((const NMSettInfoSettDetail){__VA_ARGS__})) +#define NM_SETT_INFO_SETT_DETAIL(...) (&((const NMSettInfoSettDetail) {__VA_ARGS__})) #define NM_SETT_INFO_PROPERT_TYPE_DBUS_INIT(_dbus_type, ...) {.dbus_type = _dbus_type, __VA_ARGS__} @@ -504,7 +508,7 @@ void _nm_setting_class_commit(NMSettingClass *setting_class, #define NM_SETT_INFO_PROPERT_TYPE_GPROP(_dbus_type, ...) \ NM_SETT_INFO_PROPERT_TYPE(NM_SETT_INFO_PROPERT_TYPE_GPROP_INIT(_dbus_type, __VA_ARGS__)) -#define NM_SETT_INFO_PROPERTY(...) (&((const NMSettInfoProperty){__VA_ARGS__})) +#define NM_SETT_INFO_PROPERTY(...) (&((const NMSettInfoProperty) {__VA_ARGS__})) gboolean _nm_properties_override_assert(const NMSettInfoProperty *prop_info); diff --git a/src/libnm-core-impl/nm-setting-sriov.c b/src/libnm-core-impl/nm-setting-sriov.c index 145c2b14..4dc61d82 100644 --- a/src/libnm-core-impl/nm-setting-sriov.c +++ b/src/libnm-core-impl/nm-setting-sriov.c @@ -103,7 +103,7 @@ nm_sriov_vf_new(guint index) NMSriovVF *vf; vf = g_slice_new(NMSriovVF); - *vf = (NMSriovVF){ + *vf = (NMSriovVF) { .refcount = 1, .index = index, .attributes = g_hash_table_new_full(nm_str_hash, @@ -223,7 +223,7 @@ vf_add_vlan(NMSriovVF *vf, guint vlan_id, guint qos, NMSriovVFVlanProtocol proto VFVlan *vlan; vlan = g_slice_new(VFVlan); - *vlan = (VFVlan){ + *vlan = (VFVlan) { .id = vlan_id, .qos = qos, .protocol = protocol, diff --git a/src/libnm-core-impl/nm-setting-vlan.c b/src/libnm-core-impl/nm-setting-vlan.c index 3a1f0930..5cb2470c 100644 --- a/src/libnm-core-impl/nm-setting-vlan.c +++ b/src/libnm-core-impl/nm-setting-vlan.c @@ -130,7 +130,7 @@ priority_map_new(guint32 from, guint32 to) NMVlanQosMapping *mapping; mapping = g_new(NMVlanQosMapping, 1); - *mapping = (NMVlanQosMapping){ + *mapping = (NMVlanQosMapping) { .from = from, .to = to, }; diff --git a/src/libnm-core-impl/nm-setting-wired.c b/src/libnm-core-impl/nm-setting-wired.c index 2c8562d3..e02c0a06 100644 --- a/src/libnm-core-impl/nm-setting-wired.c +++ b/src/libnm-core-impl/nm-setting-wired.c @@ -810,7 +810,7 @@ nm_setting_wired_add_s390_option(NMSettingWired *setting, const char *key, const &priv->s390_options.arr[dst_idx], (priv->s390_options.len - dst_idx) * sizeof(NMUtilsNamedValue)); } - priv->s390_options.arr[dst_idx] = (NMUtilsNamedValue){ + priv->s390_options.arr[dst_idx] = (NMUtilsNamedValue) { .name = g_strdup(key), .value_str = g_strdup(value), }; @@ -1253,7 +1253,7 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps nm_assert(priv->s390_options.len < priv->s390_options.n_alloc); - priv->s390_options.arr[priv->s390_options.len] = (NMUtilsNamedValue){ + priv->s390_options.arr[priv->s390_options.len] = (NMUtilsNamedValue) { .name = g_strdup(key), .value_str = g_strdup(val), }; diff --git a/src/libnm-core-impl/nm-setting-wireguard.c b/src/libnm-core-impl/nm-setting-wireguard.c index 4f96f742..668af1f6 100644 --- a/src/libnm-core-impl/nm-setting-wireguard.c +++ b/src/libnm-core-impl/nm-setting-wireguard.c @@ -77,7 +77,7 @@ nm_wireguard_peer_new(void) NMWireGuardPeer *self; self = g_slice_new(NMWireGuardPeer); - *self = (NMWireGuardPeer){ + *self = (NMWireGuardPeer) { .refcount = 1, .preshared_key_flags = NM_SETTING_SECRET_FLAG_NOT_REQUIRED, }; @@ -104,7 +104,7 @@ nm_wireguard_peer_new_clone(const NMWireGuardPeer *self, gboolean with_secrets) g_return_val_if_fail(NM_IS_WIREGUARD_PEER(self, TRUE), NULL); new = g_slice_new(NMWireGuardPeer); - *new = (NMWireGuardPeer){ + *new = (NMWireGuardPeer) { .refcount = 1, .public_key = g_strdup(self->public_key), .public_key_valid = self->public_key_valid, @@ -1310,7 +1310,7 @@ _peers_set(NMSettingWireGuardPrivate *priv, if (!pd_same_key) pd_same_key = g_slice_new(PeerData); - *pd_same_key = (PeerData){ + *pd_same_key = (PeerData) { .peer = peer, .public_key = public_key, .idx = priv->peers_arr->len, diff --git a/src/libnm-core-impl/nm-setting.c b/src/libnm-core-impl/nm-setting.c index ed34db76..98424c76 100644 --- a/src/libnm-core-impl/nm-setting.c +++ b/src/libnm-core-impl/nm-setting.c @@ -446,7 +446,7 @@ _nm_setting_class_commit(NMSettingClass *setting_class, const NMSettInfoProperty *property_info = &sett_info->property_infos[j]; if (property_info->param_spec) { - *(lookup_by_iter++) = (NMSettInfoPropertLookupByParamSpec){ + *(lookup_by_iter++) = (NMSettInfoPropertLookupByParamSpec) { .param_spec_as_uint = (uintptr_t) ((gpointer) property_info->param_spec), .property_info = property_info, }; @@ -4346,7 +4346,7 @@ nm_range_new(guint64 start, guint64 end) g_return_val_if_fail(start <= end, NULL); range = g_slice_new(NMRange); - *range = (NMRange){ + *range = (NMRange) { .refcount = 1, .start = start, .end = end, diff --git a/src/libnm-core-impl/nm-team-utils.c b/src/libnm-core-impl/nm-team-utils.c index 6e7f85c7..8e1cdd64 100644 --- a/src/libnm-core-impl/nm-team-utils.c +++ b/src/libnm-core-impl/nm-team-utils.c @@ -692,9 +692,9 @@ _team_setting_has_fields_any_v(const NMTeamSetting *self, return FALSE; } -#define _team_setting_has_fields_any(self, ...) \ - _team_setting_has_fields_any_v((self), \ - ((const NMTeamAttribute[]){__VA_ARGS__}), \ +#define _team_setting_has_fields_any(self, ...) \ + _team_setting_has_fields_any_v((self), \ + ((const NMTeamAttribute[]) {__VA_ARGS__}), \ NM_NARG(__VA_ARGS__)) static void diff --git a/src/libnm-core-impl/nm-utils-private.h b/src/libnm-core-impl/nm-utils-private.h index 1521c0f9..da442511 100644 --- a/src/libnm-core-impl/nm-utils-private.h +++ b/src/libnm-core-impl/nm-utils-private.h @@ -14,7 +14,7 @@ #include "nm-setting-ip-config.h" #define NM_VARIANT_ATTRIBUTE_SPEC_DEFINE(_name, _type, ...) \ - (&((const NMVariantAttributeSpec){.name = _name, .type = _type, __VA_ARGS__})) + (&((const NMVariantAttributeSpec) {.name = _name, .type = _type, __VA_ARGS__})) gboolean _nm_utils_string_slist_validate(GSList *list, const char **valid_values); diff --git a/src/libnm-core-impl/nm-utils.c b/src/libnm-core-impl/nm-utils.c index fea13a95..6528b5fb 100644 --- a/src/libnm-core-impl/nm-utils.c +++ b/src/libnm-core-impl/nm-utils.c @@ -305,14 +305,14 @@ nm_sock_addr_endpoint_get_fixed_sockaddr(NMSockAddrEndpoint *self, gpointer sock good: switch (addr_family) { case AF_INET: - *((struct sockaddr_in *) sockaddr) = (struct sockaddr_in){ + *((struct sockaddr_in *) sockaddr) = (struct sockaddr_in) { .sin_family = AF_INET, .sin_addr = addrbin.addr4_struct, .sin_port = htons(self->port), }; return TRUE; case AF_INET6: - *((struct sockaddr_in6 *) sockaddr) = (struct sockaddr_in6){ + *((struct sockaddr_in6 *) sockaddr) = (struct sockaddr_in6) { .sin6_family = AF_INET6, .sin6_addr = addrbin.addr6, .sin6_port = htons(self->port), @@ -1309,11 +1309,11 @@ nm_utils_dns_to_variant(int addr_family, const char *const *dns, gssize len) /* We can only represent the IP address on the legacy property "ipv[46].dns". * Expose what we can. */ - if (!nm_utils_dnsname_parse(addr_family, dns[i], NULL, &ip, NULL)) + if (!nm_dns_uri_parse_plain(addr_family, dns[i], NULL, &ip)) continue; if (IS_IPv4) - g_variant_builder_add(&builder, "u", ip); + g_variant_builder_add(&builder, "u", ip.addr4); else g_variant_builder_add(&builder, "@ay", nm_g_variant_new_ay_in6addr(&ip.addr6)); } @@ -2358,7 +2358,7 @@ _nm_utils_ip_addresses_from_variant(GVariant *value, int family, bool strict, GE g_set_error(error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("IP address requires fields \"dest\" and \"prefix\" (idx=%u)"), + _("IP address requires fields \"address\" and \"prefix\" (idx=%u)"), i); return NULL; } @@ -2719,9 +2719,9 @@ typedef struct { } NMQdiscAttributeSpec; static const NMQdiscAttributeSpec *const tc_qdisc_attribute_spec[] = { - &(const NMQdiscAttributeSpec){"fq_codel", tc_qdisc_fq_codel_spec}, - &(const NMQdiscAttributeSpec){"sfq", tc_qdisc_sfq_spec}, - &(const NMQdiscAttributeSpec){"tbf", tc_qdisc_tbf_spec}, + &(const NMQdiscAttributeSpec) {"fq_codel", tc_qdisc_fq_codel_spec}, + &(const NMQdiscAttributeSpec) {"sfq", tc_qdisc_sfq_spec}, + &(const NMQdiscAttributeSpec) {"tbf", tc_qdisc_tbf_spec}, NULL, }; diff --git a/src/libnm-core-impl/nm-vpn-editor-plugin.c b/src/libnm-core-impl/nm-vpn-editor-plugin.c index 6181368a..fc998b57 100644 --- a/src/libnm-core-impl/nm-vpn-editor-plugin.c +++ b/src/libnm-core-impl/nm-vpn-editor-plugin.c @@ -299,6 +299,9 @@ _nm_vpn_editor_plugin_load(const char *plugin_name, return NULL; } + /* Note that factory() shouldn't be returning errors or failing. + * We can't change its prototype as it would consistute an ABI break, + * however it returning a failure would indicate a bug in the plugin. */ editor_plugin = factory(&factory_error); if (loaded_before) { diff --git a/src/libnm-core-impl/tests/test-general.c b/src/libnm-core-impl/tests/test-general.c index 8d4ea069..d581fc79 100644 --- a/src/libnm-core-impl/tests/test-general.c +++ b/src/libnm-core-impl/tests/test-general.c @@ -560,13 +560,13 @@ test_nm_hash(void) g_assert_cmpmem(NM_HASH_SEED_16(55, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), 16, - ((guint8[16]){55, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}), + ((guint8[16]) {55, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}), 16); - g_assert_cmpmem(NM_HASH_SEED_16_U64(1), 16, ((guint8[16]){0, 0, 0, 0, 0, 0, 0, 1, 0}), 16); + g_assert_cmpmem(NM_HASH_SEED_16_U64(1), 16, ((guint8[16]) {0, 0, 0, 0, 0, 0, 0, 1, 0}), 16); g_assert_cmpmem(NM_HASH_SEED_16_U64(0x1234567890ABCDEFu), 16, - ((guint8[16]){0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, 0}), + ((guint8[16]) {0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, 0}), 16); g_assert_cmpint(c_siphash_hash(NM_HASH_SEED_16_U64(0x780E21E45489CC6Fu), (guint8 *) "foo", 3), @@ -1702,7 +1702,7 @@ static const NMDedupMultiObjClass dedup_obj_class = { }; #define DEDUP_OBJ_INIT(val_val, other_other) \ - (&((DedupObj){ \ + (&((DedupObj) { \ .parent = \ { \ .klass = &dedup_obj_class, \ @@ -1904,7 +1904,7 @@ _dedup_entry_assert_all(const NMDedupMultiEntry *entry, } } #define _dedup_entry_assert_all(entry, expected_idx, ...) \ - _dedup_entry_assert_all(entry, expected_idx, (const DedupObj *const[]){__VA_ARGS__, NULL}) + _dedup_entry_assert_all(entry, expected_idx, (const DedupObj *const[]) {__VA_ARGS__, NULL}) static void test_dedup_multi(void) @@ -3962,7 +3962,7 @@ typedef struct { typedef struct { const char *name; - DiffKey keys[33]; + DiffKey keys[41]; } DiffSetting; #define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0])) @@ -4037,6 +4037,9 @@ test_connection_diff_a_only(void) {NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT, NM_SETTING_DIFF_RESULT_IN_A}, {NM_SETTING_CONNECTION_WAIT_ACTIVATION_DELAY, NM_SETTING_DIFF_RESULT_IN_A}, {NM_SETTING_CONNECTION_DOWN_ON_POWEROFF, NM_SETTING_DIFF_RESULT_IN_A}, + {NM_SETTING_CONNECTION_IP_PING_TIMEOUT, NM_SETTING_DIFF_RESULT_IN_A}, + {NM_SETTING_CONNECTION_IP_PING_ADDRESSES, NM_SETTING_DIFF_RESULT_IN_A}, + {NM_SETTING_CONNECTION_IP_PING_ADDRESSES_REQUIRE_ALL, NM_SETTING_DIFF_RESULT_IN_A}, {NULL, NM_SETTING_DIFF_RESULT_UNKNOWN}}}, {NM_SETTING_WIRED_SETTING_NAME, { @@ -4075,6 +4078,7 @@ test_connection_diff_a_only(void) {NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID, NM_SETTING_DIFF_RESULT_IN_A}, {NM_SETTING_IP_CONFIG_DHCP_TIMEOUT, NM_SETTING_DIFF_RESULT_IN_A}, {NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME, NM_SETTING_DIFF_RESULT_IN_A}, + {NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME_V2, NM_SETTING_DIFF_RESULT_IN_A}, {NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, NM_SETTING_DIFF_RESULT_IN_A}, {NM_SETTING_IP_CONFIG_DHCP_HOSTNAME_FLAGS, NM_SETTING_DIFF_RESULT_IN_A}, {NM_SETTING_IP4_CONFIG_DHCP_FQDN, NM_SETTING_DIFF_RESULT_IN_A}, @@ -4088,9 +4092,13 @@ test_connection_diff_a_only(void) {NM_SETTING_IP4_CONFIG_DHCP_VENDOR_CLASS_IDENTIFIER, NM_SETTING_DIFF_RESULT_IN_A}, {NM_SETTING_IP_CONFIG_DHCP_REJECT_SERVERS, NM_SETTING_DIFF_RESULT_IN_A}, {NM_SETTING_IP4_CONFIG_LINK_LOCAL, NM_SETTING_DIFF_RESULT_IN_A}, + {NM_SETTING_IP4_CONFIG_DHCP_IPV6_ONLY_PREFERRED, NM_SETTING_DIFF_RESULT_IN_A}, {NM_SETTING_IP_CONFIG_AUTO_ROUTE_EXT_GW, NM_SETTING_DIFF_RESULT_IN_A}, {NM_SETTING_IP_CONFIG_REPLACE_LOCAL_RULE, NM_SETTING_DIFF_RESULT_IN_A}, {NM_SETTING_IP_CONFIG_DHCP_SEND_RELEASE, NM_SETTING_DIFF_RESULT_IN_A}, + {NM_SETTING_IP_CONFIG_ROUTED_DNS, NM_SETTING_DIFF_RESULT_IN_A}, + {NM_SETTING_IP_CONFIG_SHARED_DHCP_RANGE, NM_SETTING_DIFF_RESULT_IN_A}, + {NM_SETTING_IP_CONFIG_SHARED_DHCP_LEASE_TIME, NM_SETTING_DIFF_RESULT_IN_A}, {NULL, NM_SETTING_DIFF_RESULT_UNKNOWN}, }}, }; @@ -8671,9 +8679,11 @@ test_nm_utils_ascii_str_to_int64(void) static void test_nm_utils_strstrdictkey(void) { -#define _VALUES_STATIC(_v1, _v2) \ - { \ - .v1 = _v1, .v2 = _v2, .v_static = _nm_utils_strstrdictkey_static(_v1, _v2), \ +#define _VALUES_STATIC(_v1, _v2) \ + { \ + .v1 = _v1, \ + .v2 = _v2, \ + .v_static = _nm_utils_strstrdictkey_static(_v1, _v2), \ } const struct { const char *v1; @@ -10613,7 +10623,7 @@ test_integrate_maincontext(gconstpointer test_data) loop1 = g_main_loop_new(c1, FALSE); - d = (IntegData){ + d = (IntegData) { .loop1 = loop1, .c2 = c2, }; @@ -11389,176 +11399,179 @@ test_connection_path(void) /*****************************************************************************/ static void -_t_dnsname_1(const char *str, const char *exp_addr, const char *exp_server_name) -{ - int addr_family; - NMIPAddr exp_addr_bin; - gboolean addr_family_request; - gboolean r; - int detect_addr_family; - NMIPAddr detect_addr; - const char *detect_server_name; - int *p_detect_addr_family = &detect_addr_family; - NMIPAddr *p_detect_addr = &detect_addr; - const char **p_detect_server_name = &detect_server_name; - char str_construct_buf[100]; - char str_construct_buf2[100]; - const char *str_construct; - const char *str_construct2; - gsize l; - const char *str_normalized; - gs_free char *str_normalized_alloc = NULL; +t_dns_0(const char *str) +{ + NMDnsServer server = {}; + gboolean ret; - g_assert(str); - g_assert(exp_addr); + ret = nm_dns_uri_parse(AF_UNSPEC, str, &server); - r = nm_inet_parse_bin(AF_UNSPEC, exp_addr, &addr_family, &exp_addr_bin); - g_assert(r); - g_assert(NM_IN_SET(addr_family, AF_INET, AF_INET6)); + g_assert(!ret); +} - addr_family_request = nmtst_get_rand_bool(); - if (nmtst_get_rand_bool()) - p_detect_addr = NULL; - if ((addr_family_request || !p_detect_addr) && nmtst_get_rand_bool()) - p_detect_addr_family = NULL; - if (nmtst_get_rand_bool()) - p_detect_server_name = NULL; - - r = nm_utils_dnsname_parse(addr_family_request ? addr_family : AF_UNSPEC, - str, - p_detect_addr_family, - p_detect_addr, - p_detect_server_name); - g_assert(r); - - if (p_detect_addr_family) - g_assert_cmpint(addr_family, ==, detect_addr_family); - if (p_detect_addr) - g_assert_cmpstr(nmtst_inet_to_string(addr_family, &detect_addr), ==, exp_addr); - if (p_detect_server_name) - g_assert_cmpstr(detect_server_name, ==, exp_server_name); - - r = nm_utils_dnsname_parse(addr_family == AF_INET ? AF_INET6 : AF_INET, - str, - p_detect_addr_family, - p_detect_addr, - p_detect_server_name); - g_assert(!r); - - /* Construct the expected value. */ - str_construct = nm_utils_dnsname_construct(addr_family, - &exp_addr_bin, - exp_server_name, - str_construct_buf, - sizeof(str_construct_buf)); - g_assert(str_construct); - g_assert(str_construct == str_construct_buf); - g_assert(strlen(str_construct) < sizeof(str_construct_buf)); - - /* Check that a too short buffer causes truncation. */ - l = nmtst_get_rand_uint32() % (strlen(str_construct) + 10); - str_construct2 = nm_utils_dnsname_construct(addr_family, - &exp_addr_bin, - exp_server_name, - str_construct_buf2, - l); - if (str_construct2) { - g_assert(str_construct2 == str_construct_buf2); - g_assert_cmpstr(str_construct2, ==, str_construct); - g_assert(l > strlen(str_construct)); - } else - g_assert(l <= strlen(str_construct)); +static void +dns_uri_parse_ok(const char *str, + int addr_family, + NMDnsUriScheme scheme, + const char *addr, + int port, + const char *sname, + const char *ifname) +{ + NMDnsServer dns = {}; + char addrstr[NM_INET_ADDRSTRLEN]; + gboolean ret; - if (!nm_streq(str_construct, str)) { - _t_dnsname_1(str_construct, exp_addr, exp_server_name); - } + for (int i = 0; i < 2; i++) { + gboolean af_unspec = i; - str_normalized = nm_utils_dnsname_normalize(nmtst_get_rand_bool() ? addr_family : AF_UNSPEC, - str, - &str_normalized_alloc); - g_assert(str_normalized); - if (str_normalized_alloc) { - g_assert(str_normalized == str_normalized_alloc); - g_assert_cmpstr(str_normalized, !=, str); - } else { - g_assert(str == str_normalized); + ret = nm_dns_uri_parse(af_unspec ? AF_UNSPEC : addr_family, str, &dns); + g_assert(ret); + + g_assert_cmpint(addr_family, ==, dns.addr_family); + g_assert_cmpint(port, ==, dns.port); + g_assert_cmpstr(sname, ==, dns.servername); + g_assert_cmpstr(ifname ?: "", ==, dns.interface); + + nm_inet_ntop(dns.addr_family, &dns.addr, addrstr); + g_assert_cmpstr(addrstr, ==, addr); + + /* Parse with the wrong address family must fail */ + ret = nm_dns_uri_parse(addr_family == AF_INET ? AF_INET6 : AF_INET, str, &dns); + g_assert(!ret); } - g_assert_cmpstr(str_normalized, ==, str_construct); +} + +#define t_dns_1(str, af, scheme, addr, port, sname, ifname) \ + dns_uri_parse_ok((str), \ + (AF_##af), \ + (NM_DNS_URI_SCHEME_##scheme), \ + (addr), \ + (port), \ + (sname), \ + (ifname)) + +static void +test_dns_uri_parse(void) +{ + /* clang-format off */ + t_dns_1("dns+tls://8.8.8.8", INET, TLS, "8.8.8.8", -1, NULL, NULL); + t_dns_1("dns+tls://8.8.8.8", INET, TLS, "8.8.8.8", -1, NULL, NULL); + t_dns_1("dns+tls://1.2.3.4#name", INET, TLS, "1.2.3.4", -1, "name", NULL); + t_dns_1("dns+tls://1.2.3.4#a.b.c", INET, TLS, "1.2.3.4", -1, "a.b.c", NULL); + t_dns_1("dns+tls://1.2.3.4:53", INET, TLS, "1.2.3.4", 53, NULL, NULL); + t_dns_1("dns+tls://1.2.3.4:53#foobar", INET, TLS, "1.2.3.4", 53, "foobar", NULL); + t_dns_1("dns+tls://192.168.120.250:99", INET, TLS, "192.168.120.250", 99, NULL, NULL); + t_dns_1("dns+udp://8.8.8.8:65535", INET, UDP, "8.8.8.8", 65535, NULL, NULL); + + t_dns_1("dns+udp://[fd01::1]", INET6, UDP, "fd01::1", -1, NULL, NULL); + t_dns_1("dns+tls://[fd01::2]:5353", INET6, UDP, "fd01::2", 5353, NULL, NULL); + t_dns_1("dns+tls://[::1]#name", INET6, UDP, "::1", -1, "name", NULL); + t_dns_1("dns+tls://[::2]:65535#name", INET6, UDP, "::2", 65535, "name", NULL); + t_dns_1("dns+udp://[::ffff:1.2.3.4]", INET6, UDP, "::ffff:1.2.3.4", -1, NULL, NULL); + t_dns_1("dns+tls://[fe80::1%eth0]", INET6, UDP, "fe80::1", -1, NULL, "eth0"); + t_dns_1("dns+tls://[fe80::2%en1]:53#a", INET6, UDP, "fe80::2", 53, "a", "en1"); + t_dns_1("dns+tls://[fe80::1%en3456789012345]", INET6, UDP, "fe80::1", -1, NULL, "en3456789012345"); + + t_dns_1("1.2.3.4", INET, NONE, "1.2.3.4", -1, NULL, NULL); + t_dns_1("1.2.3.4#foo", INET, NONE, "1.2.3.4", -1, "foo", NULL); + t_dns_1("1::#x", INET6, NONE, "1::", -1, "x", NULL); + t_dns_1("1::0#x", INET6, NONE, "1::", -1, "x", NULL); + t_dns_1("192.168.0.1", INET, NONE, "192.168.0.1", -1, NULL, NULL); + t_dns_1("192.168.0.1#tst.com", INET, NONE, "192.168.0.1", -1, "tst.com", NULL); + t_dns_1("fe80::18", INET6, NONE, "fe80::18", -1, NULL, NULL); + t_dns_1("fe80::18#foo.com", INET6, NONE, "fe80::18", -1, "foo.com", NULL); + /* clang-format on */ - nm_clear_g_free(&str_normalized_alloc); - str_normalized = nm_utils_dnsname_normalize(addr_family == AF_INET ? AF_INET6 : AF_INET, - str, - &str_normalized_alloc); - g_assert(!str_normalized); - g_assert(!str_normalized_alloc); + t_dns_0("http://8.8.8.8"); /* unsupported schema */ + t_dns_0("dns+udp://1.2.3.4#name"); /* servername not supported for plain UDP */ + t_dns_0("dns+tls://1.2.3"); /* invalid address */ + t_dns_0("dns+tls://fd01::1"); /* IPv6 requires brackets */ + t_dns_0("dns+tls://[fd13:a:aaaa]"); /* invalid address */ + t_dns_0("dns+tls://1.2.3.4:1:1"); /* invalid syntax */ + t_dns_0("dns+tls://1.2.3.4#name#name"); /* invalid syntax */ + t_dns_0("dns+tls://1.2.3.4%eth0"); /* interface only allowed for IPv6 */ + t_dns_0("dns+tls://[2001::1%eth0]"); /* interface only allowed for IPv6 link-local */ + t_dns_0("dns+tls://[fe80::1%en34567890123456]"); /* interface name too long */ + t_dns_0("1.2.3.4#"); + t_dns_0("1::0#"); + t_dns_0("192.168.0.1:53"); + t_dns_0("192.168.0.1:53#example.com"); + t_dns_0("fe80::18%19"); + t_dns_0("fe80::18%lo"); + t_dns_0("[fe80::18]:53"); + t_dns_0("[fe80::18]:53%19"); + t_dns_0("[fe80::18]:53%lo"); + t_dns_0("fe80::18%19#hoge.com"); + t_dns_0("[fe80::18]:53#hoge.com"); + t_dns_0("[fe80::18]:53%19"); + t_dns_0("[fe80::18]:53%19#hoge.com"); + t_dns_0("[fe80::18]:53%lo"); + t_dns_0("[fe80::18]:53%lo#hoge.com"); +} + +static void +test_dns_uri_parse_plain(void) +{ + struct { + const char *input; + int input_af; + gboolean result; + const char *addrstr; + } values[] = { + {"1.2.3.4", AF_INET, TRUE, "1.2.3.4"}, + {"1.2.3.4", AF_INET6, FALSE, NULL}, + {"1.2.3.4", AF_UNSPEC, TRUE, "1.2.3.4"}, + {"1234:5555:ffff:dddd::4321", AF_INET, FALSE, NULL}, + {"1234:5555:ffff:dddd::4321", AF_INET6, TRUE, "1234:5555:ffff:dddd::4321"}, + {"1234:5555:ffff:dddd::4321", AF_UNSPEC, TRUE, "1234:5555:ffff:dddd::4321"}, + {"192.0.2.1#example.com", AF_INET, TRUE, "192.0.2.1"}, + {"192.0.2.1#example.com", AF_UNSPEC, TRUE, "192.0.2.1"}, + {"192.0.2.1#example.com", AF_INET6, FALSE, NULL}, + {"dns+tls://1.2.3.4", AF_INET, FALSE, NULL}, + {"dns+tls://[fd01::1]", AF_INET, FALSE, NULL}, + {"dns+udp://1.2.3.4:53", AF_INET, TRUE, "1.2.3.4"}, + {"dns+udp://1.2.3.4:54", AF_INET, FALSE, NULL}, + {"dns+udp://[fd01::1]", AF_INET6, TRUE, "fd01::1"}, + {"dns+udp://[fd01::1]:53", AF_INET6, TRUE, "fd01::1"}, + {"dns+udp://[fd01::1]:60000", AF_INET, FALSE, NULL}, + }; + guint i; + + for (i = 0; i < G_N_ELEMENTS(values); i++) { + char addrstr[NM_INET_ADDRSTRLEN]; + gboolean result; + NMIPAddr addr; + + result = nm_dns_uri_parse_plain(values[i].input_af, values[i].input, addrstr, &addr); + g_assert_cmpint(result, ==, values[i].result); + if (result) { + char buf[NM_INET_ADDRSTRLEN]; + + nm_inet_ntop(strchr(addrstr, ':') ? AF_INET6 : AF_INET, addr.addr_ptr, buf); + g_assert_cmpstr(buf, ==, addrstr); + g_assert_cmpstr(addrstr, ==, values[i].addrstr); + } + } } static void -_t_dnsname_0(const char *str) +t_dns_uri_normalize(const char *input, const char *expected) { - gboolean addr_family_request; - int detect_addr_family; - NMIPAddr detect_addr; - const char *detect_server_name; - int *p_detect_addr_family = &detect_addr_family; - NMIPAddr *p_detect_addr = &detect_addr; - const char **p_detect_server_name = &detect_server_name; - const char *str_normalized; - gs_free char *str_normalized_alloc = NULL; - gboolean r; + const char *str; + gs_free char *str_free = NULL; - g_assert(str); + str = nm_dns_uri_normalize(AF_UNSPEC, input, &str_free); + g_assert_cmpstr(str, ==, expected); +} - addr_family_request = nmtst_get_rand_bool(); - if (nmtst_get_rand_bool()) - p_detect_addr = NULL; - if ((addr_family_request || !p_detect_addr) && nmtst_get_rand_bool()) - p_detect_addr_family = NULL; - if (nmtst_get_rand_bool()) - p_detect_server_name = NULL; - - r = nm_utils_dnsname_parse(addr_family_request ? nmtst_rand_select(AF_INET, AF_INET6) - : AF_UNSPEC, - str, - p_detect_addr_family, - p_detect_addr, - p_detect_server_name); - g_assert(!r); - - str_normalized = nm_utils_dnsname_normalize(nmtst_rand_select(AF_UNSPEC, AF_INET, AF_INET6), - str, - &str_normalized_alloc); - g_assert(!str_normalized); - g_assert(!str_normalized_alloc); -} - -static void -test_dnsname(void) -{ - _t_dnsname_1("1.2.3.4", "1.2.3.4", NULL); - _t_dnsname_1("1.2.3.4#foo", "1.2.3.4", "foo"); - _t_dnsname_1("1::#x", "1::", "x"); - _t_dnsname_1("1::0#x", "1::", "x"); - _t_dnsname_1("192.168.0.1", "192.168.0.1", NULL); - _t_dnsname_1("192.168.0.1#test.com", "192.168.0.1", "test.com"); - _t_dnsname_1("fe80::18", "fe80::18", NULL); - _t_dnsname_1("fe80::18#hoge.com", "fe80::18", "hoge.com"); - - _t_dnsname_0("1.2.3.4#"); - _t_dnsname_0("1::0#"); - _t_dnsname_0("192.168.0.1:53"); - _t_dnsname_0("192.168.0.1:53#example.com"); - _t_dnsname_0("fe80::18%19"); - _t_dnsname_0("fe80::18%lo"); - _t_dnsname_0("[fe80::18]:53"); - _t_dnsname_0("[fe80::18]:53%19"); - _t_dnsname_0("[fe80::18]:53%lo"); - _t_dnsname_0("fe80::18%19#hoge.com"); - _t_dnsname_0("[fe80::18]:53#hoge.com"); - _t_dnsname_0("[fe80::18]:53%19"); - _t_dnsname_0("[fe80::18]:53%19#hoge.com"); - _t_dnsname_0("[fe80::18]:53%lo"); - _t_dnsname_0("[fe80::18]:53%lo#hoge.com"); +static void +test_dns_uri_normalize(void) +{ + t_dns_uri_normalize("8.8.8.8", "8.8.8.8"); + t_dns_uri_normalize("dns+tls://[2001:0:0::1234]:999#name", "dns+tls://[2001::1234]:999#name"); + t_dns_uri_normalize("dns+udp://[0::1]:0123", "dns+udp://[::1]:123"); + t_dns_uri_normalize("8.8.8.888", NULL); } /*****************************************************************************/ @@ -11937,7 +11950,9 @@ main(int argc, char **argv) g_test_add_func("/core/general/test_system_encodings", test_system_encodings); g_test_add_func("/core/general/test_direct_string_is_refstr", test_direct_string_is_refstr); g_test_add_func("/core/general/test_connection_path", test_connection_path); - g_test_add_func("/core/general/test_dnsname", test_dnsname); + g_test_add_func("/core/general/test_dns_uri_parse", test_dns_uri_parse); + g_test_add_func("/core/general/test_dns_uri_get_legacy", test_dns_uri_parse_plain); + g_test_add_func("/core/general/test_dns_uri_normalize", test_dns_uri_normalize); g_test_add_func("/core/general/test_dhcp_iaid_hexstr", test_dhcp_iaid_hexstr); return g_test_run(); diff --git a/src/libnm-core-impl/tests/test-keyfile.c b/src/libnm-core-impl/tests/test-keyfile.c index 1912782e..5c66196c 100644 --- a/src/libnm-core-impl/tests/test-keyfile.c +++ b/src/libnm-core-impl/tests/test-keyfile.c @@ -943,7 +943,7 @@ test_invalid_option(void) nm_setting_option_set_boolean(s_ethtool, NM_ETHTOOL_OPTNAME_PAUSE_RX, TRUE); - data = (InvalidOptionWriteData){}; + data = (InvalidOptionWriteData) {}; kf = nm_keyfile_write(con, NM_KEYFILE_HANDLER_FLAGS_NONE, _invalid_option_write_handler, @@ -956,7 +956,7 @@ test_invalid_option(void) nmtst_assert_connection_verifies_without_normalization(con); - data = (InvalidOptionWriteData){}; + data = (InvalidOptionWriteData) {}; kf = nm_keyfile_write(con, NM_KEYFILE_HANDLER_FLAGS_NONE, _invalid_option_write_handler, @@ -967,7 +967,7 @@ test_invalid_option(void) nm_setting_option_set(s_ethtool, "bogus", g_variant_new_int64(0)); - data = (InvalidOptionWriteData){ + data = (InvalidOptionWriteData) { .expect = TRUE, }; kf = nm_keyfile_write(con, diff --git a/src/libnm-core-impl/tests/test-setting.c b/src/libnm-core-impl/tests/test-setting.c index f3309166..2064162a 100644 --- a/src/libnm-core-impl/tests/test-setting.c +++ b/src/libnm-core-impl/tests/test-setting.c @@ -799,29 +799,29 @@ static void test_bond_compare(void) { test_bond_compare_options(TRUE, - ((const char *[]){"mode", "balance-rr", "miimon", "1", NULL}), - ((const char *[]){"mode", "balance-rr", "miimon", "1", NULL})); + ((const char *[]) {"mode", "balance-rr", "miimon", "1", NULL}), + ((const char *[]) {"mode", "balance-rr", "miimon", "1", NULL})); test_bond_compare_options(FALSE, - ((const char *[]){"mode", "balance-rr", "miimon", "1", NULL}), - ((const char *[]){"mode", "balance-rr", "miimon", "2", NULL})); + ((const char *[]) {"mode", "balance-rr", "miimon", "1", NULL}), + ((const char *[]) {"mode", "balance-rr", "miimon", "2", NULL})); test_bond_compare_options(FALSE, - ((const char *[]){"miimon", "1", NULL}), - ((const char *[]){"miimon", "1", "updelay", "0", NULL})); + ((const char *[]) {"miimon", "1", NULL}), + ((const char *[]) {"miimon", "1", "updelay", "0", NULL})); test_bond_compare_options(FALSE, - ((const char *[]){"num_grat_arp", "2", NULL}), - ((const char *[]){"num_grat_arp", "1", NULL})); + ((const char *[]) {"num_grat_arp", "2", NULL}), + ((const char *[]) {"num_grat_arp", "1", NULL})); test_bond_compare_options(FALSE, - ((const char *[]){"num_grat_arp", "3", NULL}), - ((const char *[]){"num_unsol_na", "3", NULL})); + ((const char *[]) {"num_grat_arp", "3", NULL}), + ((const char *[]) {"num_unsol_na", "3", NULL})); test_bond_compare_options(FALSE, - ((const char *[]){"num_grat_arp", "4", NULL}), - ((const char *[]){"num_unsol_na", "4", "num_grat_arp", "4", NULL})); + ((const char *[]) {"num_grat_arp", "4", NULL}), + ((const char *[]) {"num_unsol_na", "4", "num_grat_arp", "4", NULL})); test_bond_compare_options(FALSE, - ((const char *[]){"mode", "balance-rr", "miimon", "100", NULL}), - ((const char *[]){"mode", "balance-rr", NULL})); + ((const char *[]) {"mode", "balance-rr", "miimon", "100", NULL}), + ((const char *[]) {"mode", "balance-rr", NULL})); } static void @@ -856,20 +856,25 @@ static void test_bond_normalize(void) { test_bond_normalize_options( - ((const char *[]){"mode", "802.3ad", "ad_actor_system", "00:02:03:04:05:06", NULL}), - ((const char *[]){"mode", "802.3ad", "ad_actor_system", "00:02:03:04:05:06", NULL})); - test_bond_normalize_options(((const char *[]){"mode", "1", "miimon", "1", NULL}), - ((const char *[]){"mode", "active-backup", "miimon", "1", NULL})); + ((const char *[]) {"mode", "802.3ad", "ad_actor_system", "00:02:03:04:05:06", NULL}), + ((const char *[]) {"mode", "802.3ad", "ad_actor_system", "00:02:03:04:05:06", NULL})); + test_bond_normalize_options(((const char *[]) {"mode", "1", "miimon", "1", NULL}), + ((const char *[]) {"mode", "active-backup", "miimon", "1", NULL})); test_bond_normalize_options( - ((const char *[]){"mode", "balance-alb", "tlb_dynamic_lb", "1", NULL}), - ((const char *[]){"mode", "balance-alb", "tlb_dynamic_lb", "1", NULL})); + ((const char *[]) {"mode", "balance-alb", "tlb_dynamic_lb", "1", NULL}), + ((const char *[]) {"mode", "balance-alb", "tlb_dynamic_lb", "1", NULL})); test_bond_normalize_options( - ((const char *[]){"mode", "balance-tlb", "tlb_dynamic_lb", "1", NULL}), - ((const char *[]){"mode", "balance-tlb", "tlb_dynamic_lb", "1", NULL})); + ((const char *[]) {"mode", "balance-tlb", "tlb_dynamic_lb", "1", NULL}), + ((const char *[]) {"mode", "balance-tlb", "tlb_dynamic_lb", "1", NULL})); test_bond_normalize_options( - ((const char - *[]){"mode", "balance-rr", "ad_actor_sys_prio", "4", "packets_per_slave", "3", NULL}), - ((const char *[]){"mode", "balance-rr", "packets_per_slave", "3", NULL})); + ((const char *[]) {"mode", + "balance-rr", + "ad_actor_sys_prio", + "4", + "packets_per_slave", + "3", + NULL}), + ((const char *[]) {"mode", "balance-rr", "packets_per_slave", "3", NULL})); } /*****************************************************************************/ @@ -2379,6 +2384,85 @@ test_ethtool_eee(void) /*****************************************************************************/ static void +test_ethtool_fec(void) +{ + gs_unref_object NMConnection *con = NULL; + gs_unref_object NMConnection *con2 = NULL; + gs_unref_object NMConnection *con3 = NULL; + gs_unref_variant GVariant *variant = NULL; + gs_free_error GError *error = NULL; + nm_auto_unref_keyfile GKeyFile *keyfile = NULL; + NMSettingConnection *s_con; + NMSettingEthtool *s_ethtool; + NMSettingEthtool *s_ethtool2; + NMSettingEthtool *s_ethtool3; + guint32 out_value; + guint32 expected_fec_mode = + NM_SETTING_ETHTOOL_FEC_MODE_AUTO | NM_SETTING_ETHTOOL_FEC_MODE_BASER; + + con = + nmtst_create_minimal_connection("ethtool-fec", NULL, NM_SETTING_WIRED_SETTING_NAME, &s_con); + s_ethtool = NM_SETTING_ETHTOOL(nm_setting_ethtool_new()); + nm_connection_add_setting(con, NM_SETTING(s_ethtool)); + + nm_setting_option_set_uint32(NM_SETTING(s_ethtool), + NM_ETHTOOL_OPTNAME_FEC_MODE, + expected_fec_mode); + + g_assert_true(nm_setting_option_get_uint32(NM_SETTING(s_ethtool), + NM_ETHTOOL_OPTNAME_FEC_MODE, + &out_value)); + g_assert_true(out_value == expected_fec_mode); + + nmtst_connection_normalize(con); + + variant = nm_connection_to_dbus(con, NM_CONNECTION_SERIALIZE_ALL); + + con2 = nm_simple_connection_new_from_dbus(variant, &error); + nmtst_assert_success(con2, error); + + s_ethtool2 = NM_SETTING_ETHTOOL(nm_connection_get_setting(con2, NM_TYPE_SETTING_ETHTOOL)); + + g_assert_true(nm_setting_option_get_uint32(NM_SETTING(s_ethtool2), + NM_ETHTOOL_OPTNAME_FEC_MODE, + &out_value)); + g_assert_true(out_value == expected_fec_mode); + + nmtst_assert_connection_verifies_without_normalization(con2); + + nmtst_assert_connection_equals(con, FALSE, con2, FALSE); + + con2 = nm_simple_connection_new_from_dbus(variant, &error); + nmtst_assert_success(con2, error); + + keyfile = nm_keyfile_write(con, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, &error); + nmtst_assert_success(keyfile, error); + + con3 = nm_keyfile_read(keyfile, + "/ignored/current/working/directory/for/loading/relative/paths", + NM_KEYFILE_HANDLER_FLAGS_NONE, + NULL, + NULL, + &error); + nmtst_assert_success(con3, error); + + nm_keyfile_read_ensure_id(con3, "unused-because-already-has-id"); + nm_keyfile_read_ensure_uuid(con3, "unused-because-already-has-uuid"); + + nmtst_connection_normalize(con3); + + nmtst_assert_connection_equals(con, FALSE, con3, FALSE); + + s_ethtool3 = NM_SETTING_ETHTOOL(nm_connection_get_setting(con3, NM_TYPE_SETTING_ETHTOOL)); + + g_assert_true(nm_setting_option_get_uint32(NM_SETTING(s_ethtool3), + NM_ETHTOOL_OPTNAME_FEC_MODE, + &out_value)); + g_assert_true(out_value == expected_fec_mode); +} +/*****************************************************************************/ + +static void test_sriov_vf(void) { NMSriovVF *vf1, *vf2; @@ -5481,6 +5565,7 @@ main(int argc, char **argv) g_test_add_func("/libnm/settings/ethtool/ring", test_ethtool_ring); g_test_add_func("/libnm/settings/ethtool/pause", test_ethtool_pause); g_test_add_func("/libnm/settings/ethtool/eee", test_ethtool_eee); + g_test_add_func("/libnm/settings/ethtool/fec", test_ethtool_fec); g_test_add_func("/libnm/settings/6lowpan/1", test_6lowpan_1); |