diff options
author | Beniamino Galvani <bgalvani@redhat.com> | 2020-11-16 17:04:54 +0100 |
---|---|---|
committer | Beniamino Galvani <bgalvani@redhat.com> | 2020-11-16 17:04:54 +0100 |
commit | 090c360ca40e9cc3435e493db186df6b3584b6bc (patch) | |
tree | b325b2afdd838ce8090c15151d5e34d1c9e8b801 | |
parent | 5b7ce438d9333b6add7b7924f9e2902d91dee335 (diff) | |
parent | 09c83871144a5154a0b3003b77fbbd69f2c758db (diff) | |
download | NetworkManager-090c360ca40e9cc3435e493db186df6b3584b6bc.tar.gz |
merge: branch 'bg/hostname-setting-rh1766944'
https://bugzilla.redhat.com/show_bug.cgi?id=1766944
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/669
30 files changed, 1088 insertions, 130 deletions
diff --git a/.clang-format b/.clang-format index f0331adefc..33a0c63993 100644 --- a/.clang-format +++ b/.clang-format @@ -66,9 +66,12 @@ SpacesInContainerLiterals: false SpacesInParentheses: false ForEachMacros: ['c_list_for_each', + 'c_list_for_each_prev', + 'c_list_for_each_prev_safe', 'c_list_for_each_continue', 'c_list_for_each_entry', 'c_list_for_each_entry_continue', + 'c_list_for_each_entry_prev', 'c_list_for_each_entry_safe', 'c_list_for_each_entry_safe_continue', 'c_list_for_each_entry_safe_unlink', @@ -93,7 +96,6 @@ ForEachMacros: ['c_list_for_each', 'ndp_msg_opt_rdnss_for_each_addr', 'nla_for_each_attr', 'nla_for_each_nested', - 'nm_c_list_for_each_entry_prev', 'nm_dedup_multi_iter_for_each', 'nm_ip_config_iter_ip4_address_for_each', 'nm_ip_config_iter_ip4_route_for_each', @@ -107,6 +109,7 @@ ForEachMacros: ['c_list_for_each', 'nm_l3_config_data_iter_ip6_route_for_each', 'nm_l3_config_data_iter_obj_for_each', 'nm_manager_for_each_active_connection', + 'nm_manager_for_each_active_connection_prev', 'nm_manager_for_each_active_connection_safe', 'nm_manager_for_each_device', 'nm_manager_for_each_device_safe', diff --git a/Makefile.am b/Makefile.am index e05f759bbc..12b9736d2f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -943,6 +943,7 @@ libnm_core_lib_h_pub_real = \ libnm-core/nm-setting-ethtool.h \ libnm-core/nm-setting-generic.h \ libnm-core/nm-setting-gsm.h \ + libnm-core/nm-setting-hostname.h \ libnm-core/nm-setting-infiniband.h \ libnm-core/nm-setting-ip-config.h \ libnm-core/nm-setting-ip-tunnel.h \ @@ -1017,6 +1018,7 @@ libnm_core_lib_c_settings_real = \ libnm-core/nm-setting-ethtool.c \ libnm-core/nm-setting-generic.c \ libnm-core/nm-setting-gsm.c \ + libnm-core/nm-setting-hostname.c \ libnm-core/nm-setting-infiniband.c \ libnm-core/nm-setting-ip-config.c \ libnm-core/nm-setting-ip-tunnel.c \ diff --git a/clients/cli/connections.c b/clients/cli/connections.c index a321e53999..6ff48b84c5 100644 --- a/clients/cli/connections.c +++ b/clients/cli/connections.c @@ -881,7 +881,8 @@ const NmcMetaGenericInfo "," NM_SETTING_6LOWPAN_SETTING_NAME "," NM_SETTING_WIREGUARD_SETTING_NAME \ "," NM_SETTING_PROXY_SETTING_NAME "," NM_SETTING_TC_CONFIG_SETTING_NAME \ "," NM_SETTING_SRIOV_SETTING_NAME "," NM_SETTING_ETHTOOL_SETTING_NAME \ - "," NM_SETTING_OVS_DPDK_SETTING_NAME /* NM_SETTING_DUMMY_SETTING_NAME NM_SETTING_WIMAX_SETTING_NAME */ + "," NM_SETTING_OVS_DPDK_SETTING_NAME \ + "," NM_SETTING_HOSTNAME_SETTING_NAME /* NM_SETTING_DUMMY_SETTING_NAME NM_SETTING_WIMAX_SETTING_NAME */ const NmcMetaGenericInfo *const nmc_fields_con_active_details_groups[] = { NMC_META_GENERIC_WITH_NESTED("GENERAL", metagen_con_active_general), /* 0 */ diff --git a/clients/cli/generate-docs-nm-settings-nmcli.xml.in b/clients/cli/generate-docs-nm-settings-nmcli.xml.in index f2f589fe8d..3c3c3f9d41 100644 --- a/clients/cli/generate-docs-nm-settings-nmcli.xml.in +++ b/clients/cli/generate-docs-nm-settings-nmcli.xml.in @@ -564,6 +564,16 @@ <property name="mtu" description="If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple frames." /> </setting> + <setting name="hostname" > + <property name="priority" + description="The relative priority of this connection to determine the system hostname. A lower numerical value is better (higher priority). A connection with higher priority is considered before connections with lower priority. If the value is zero, it can be overridden by a global value from NetworkManager configuration. If the property doesn't have a value in the global configuration, the value is assumed to be 100. Negative values have the special effect of excluding other connections with a greater numerical priority value; so in presence of at least one negative priority, only connections with the lowest priority value will be used to determine the hostname." /> + <property name="from-dhcp" + description="Whether the system hostname can be determined from DHCP on this connection. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_TRUE (1)." /> + <property name="from-dns-lookup" + description="Whether the system hostname can be determined from reverse DNS lookup of addresses on this device. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_TRUE (1)." /> + <property name="only-from-default" + description="If set to NM_TERNARY_TRUE (1), NetworkManager attempts to get the hostname via DHCPv4/DHCPv6 or reverse DNS lookup on this device only when the device has the default route for the given address family (IPv4/IPv6). If set to NM_TERNARY_FALSE (0), the hostname can be set from this device even if it doesn't have the default route. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_TRUE (1)." /> + </setting> <setting name="infiniband" > <property name="mac-address" alias="mac" diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c index 86b555fe5f..35758b8f3a 100644 --- a/clients/common/nm-meta-setting-desc.c +++ b/clients/common/nm-meta-setting-desc.c @@ -5634,6 +5634,24 @@ static const NMMetaPropertyInfo *const property_infos_GSM[] = { }; #undef _CURRENT_NM_META_SETTING_TYPE +#define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_HOSTNAME +static const NMMetaPropertyInfo *const property_infos_HOSTNAME[] = { + PROPERTY_INFO (NM_SETTING_HOSTNAME_PRIORITY, DESCRIBE_DOC_NM_SETTING_HOSTNAME_PRIORITY, + .property_type = &_pt_gobject_int, + ), + PROPERTY_INFO (NM_SETTING_HOSTNAME_FROM_DHCP, DESCRIBE_DOC_NM_SETTING_HOSTNAME_FROM_DHCP, + .property_type = &_pt_gobject_enum, + ), + PROPERTY_INFO (NM_SETTING_HOSTNAME_FROM_DNS_LOOKUP, DESCRIBE_DOC_NM_SETTING_HOSTNAME_FROM_DNS_LOOKUP, + .property_type = &_pt_gobject_enum, + ), + PROPERTY_INFO (NM_SETTING_HOSTNAME_ONLY_FROM_DEFAULT, DESCRIBE_DOC_NM_SETTING_HOSTNAME_ONLY_FROM_DEFAULT, + .property_type = &_pt_gobject_enum, + ), + NULL +}; + +#undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_INFINIBAND static const NMMetaPropertyInfo *const property_infos_INFINIBAND[] = { PROPERTY_INFO_WITH_DESC (NM_SETTING_INFINIBAND_MAC_ADDRESS, @@ -7936,6 +7954,7 @@ _setting_init_fcn_wireless (ARGS_SETTING_INIT_FCN) #define SETTING_PRETTY_NAME_ETHTOOL N_("Ethtool settings") #define SETTING_PRETTY_NAME_GENERIC N_("Generic settings") #define SETTING_PRETTY_NAME_GSM N_("GSM mobile broadband connection") +#define SETTING_PRETTY_NAME_HOSTNAME N_("Hostname settings") #define SETTING_PRETTY_NAME_INFINIBAND N_("InfiniBand connection") #define SETTING_PRETTY_NAME_IP4_CONFIG N_("IPv4 protocol") #define SETTING_PRETTY_NAME_IP6_CONFIG N_("IPv6 protocol") @@ -8073,6 +8092,7 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = { ), .setting_init_fcn = _setting_init_fcn_gsm, ), + SETTING_INFO (HOSTNAME), SETTING_INFO (INFINIBAND, .valid_parts = NM_META_SETTING_VALID_PARTS ( NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), @@ -8284,6 +8304,7 @@ static const NMMetaSettingValidPartItem *const valid_settings_noslave[] = { NM_META_SETTING_VALID_PART_ITEM(MATCH, FALSE), NM_META_SETTING_VALID_PART_ITEM(IP4_CONFIG, FALSE), NM_META_SETTING_VALID_PART_ITEM(IP6_CONFIG, FALSE), + NM_META_SETTING_VALID_PART_ITEM(HOSTNAME, FALSE), NM_META_SETTING_VALID_PART_ITEM(TC_CONFIG, FALSE), NM_META_SETTING_VALID_PART_ITEM(PROXY, FALSE), NULL, diff --git a/clients/common/settings-docs.h.in b/clients/common/settings-docs.h.in index 78198ec973..b9231752f4 100644 --- a/clients/common/settings-docs.h.in +++ b/clients/common/settings-docs.h.in @@ -203,6 +203,10 @@ #define DESCRIBE_DOC_NM_SETTING_GSM_SIM_ID N_("The SIM card unique identifier (as given by the WWAN management service) which this connection applies to. If given, the connection will apply to any device also allowed by \"device-id\" which contains a SIM card matching the given identifier.") #define DESCRIBE_DOC_NM_SETTING_GSM_SIM_OPERATOR_ID N_("A MCC/MNC string like \"310260\" or \"21601\" identifying the specific mobile network operator which this connection applies to. If given, the connection will apply to any device also allowed by \"device-id\" and \"sim-id\" which contains a SIM card provisioned by the given operator.") #define DESCRIBE_DOC_NM_SETTING_GSM_USERNAME N_("The username used to authenticate with the network, if required. Many providers do not require a username, or accept any username. But if a username is required, it is specified here.") +#define DESCRIBE_DOC_NM_SETTING_HOSTNAME_FROM_DHCP N_("Whether the system hostname can be determined from DHCP on this connection. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_TRUE (1).") +#define DESCRIBE_DOC_NM_SETTING_HOSTNAME_FROM_DNS_LOOKUP N_("Whether the system hostname can be determined from reverse DNS lookup of addresses on this device. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_TRUE (1).") +#define DESCRIBE_DOC_NM_SETTING_HOSTNAME_ONLY_FROM_DEFAULT N_("If set to NM_TERNARY_TRUE (1), NetworkManager attempts to get the hostname via DHCPv4/DHCPv6 or reverse DNS lookup on this device only when the device has the default route for the given address family (IPv4/IPv6). If set to NM_TERNARY_FALSE (0), the hostname can be set from this device even if it doesn't have the default route. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_TRUE (1).") +#define DESCRIBE_DOC_NM_SETTING_HOSTNAME_PRIORITY N_("The relative priority of this connection to determine the system hostname. A lower numerical value is better (higher priority). A connection with higher priority is considered before connections with lower priority. If the value is zero, it can be overridden by a global value from NetworkManager configuration. If the property doesn't have a value in the global configuration, the value is assumed to be 100. Negative values have the special effect of excluding other connections with a greater numerical priority value; so in presence of at least one negative priority, only connections with the lowest priority value will be used to determine the hostname.") #define DESCRIBE_DOC_NM_SETTING_INFINIBAND_MAC_ADDRESS N_("If specified, this connection will only apply to the IPoIB device whose permanent MAC address matches. This property does not change the MAC address of the device (i.e. MAC spoofing).") #define DESCRIBE_DOC_NM_SETTING_INFINIBAND_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple frames.") #define DESCRIBE_DOC_NM_SETTING_INFINIBAND_P_KEY N_("The InfiniBand P_Key to use for this device. A value of -1 means to use the default P_Key (aka \"the P_Key at index 0\"). Otherwise, it is a 16-bit unsigned integer, whose high bit is set if it is a \"full membership\" P_Key.") diff --git a/docs/libnm/libnm-docs.xml b/docs/libnm/libnm-docs.xml index d0be0eb475..0a70694d3f 100644 --- a/docs/libnm/libnm-docs.xml +++ b/docs/libnm/libnm-docs.xml @@ -324,6 +324,7 @@ print ("NetworkManager version " + client.get_version())]]></programlisting></in <xi:include href="xml/nm-setting-ethtool.xml"/> <xi:include href="xml/nm-setting-generic.xml"/> <xi:include href="xml/nm-setting-gsm.xml"/> + <xi:include href="xml/nm-setting-hostname.xml"/> <xi:include href="xml/nm-setting-infiniband.xml"/> <xi:include href="xml/nm-setting-ip4-config.xml"/> <xi:include href="xml/nm-setting-ip6-config.xml"/> diff --git a/libnm-core/meson.build b/libnm-core/meson.build index 7b59a8c204..15d8931c0f 100644 --- a/libnm-core/meson.build +++ b/libnm-core/meson.build @@ -33,6 +33,7 @@ libnm_core_headers = files( 'nm-setting-ethtool.h', 'nm-setting-generic.h', 'nm-setting-gsm.h', + 'nm-setting-hostname.h', 'nm-setting-infiniband.h', 'nm-setting-ip-config.h', 'nm-setting-ip-tunnel.h', @@ -134,6 +135,7 @@ libnm_core_settings_sources = files( 'nm-setting-ethtool.c', 'nm-setting-generic.c', 'nm-setting-gsm.c', + 'nm-setting-hostname.c', 'nm-setting-infiniband.c', 'nm-setting-ip-config.c', 'nm-setting-ip-tunnel.c', diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index fcc38565d3..c3beb71ea3 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -37,6 +37,7 @@ #include "nm-setting-dummy.h" #include "nm-setting-generic.h" #include "nm-setting-gsm.h" +#include "nm-setting-hostname.h" #include "nm-setting-infiniband.h" #include "nm-setting-ip-tunnel.h" #include "nm-setting-ip4-config.h" diff --git a/libnm-core/nm-core-types.h b/libnm-core/nm-core-types.h index 64d6464e2b..cb940a1ee9 100644 --- a/libnm-core/nm-core-types.h +++ b/libnm-core/nm-core-types.h @@ -28,6 +28,7 @@ typedef struct _NMSettingDummy NMSettingDummy; typedef struct _NMSettingEthtool NMSettingEthtool; typedef struct _NMSettingGeneric NMSettingGeneric; typedef struct _NMSettingGsm NMSettingGsm; +typedef struct _NMSettingHostname NMSettingHostname; typedef struct _NMSettingIP4Config NMSettingIP4Config; typedef struct _NMSettingIP6Config NMSettingIP6Config; typedef struct _NMSettingIPConfig NMSettingIPConfig; diff --git a/libnm-core/nm-setting-hostname.c b/libnm-core/nm-setting-hostname.c new file mode 100644 index 0000000000..8218978705 --- /dev/null +++ b/libnm-core/nm-setting-hostname.c @@ -0,0 +1,339 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +/* + * Copyright (C) 2020 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-setting-hostname.h" + +#include "nm-setting-private.h" +#include "nm-utils-private.h" + +/** + * SECTION:nm-setting-hostname + * @short_description: Contains properties related to the hostname + * @include: nm-setting-hostname.h + **/ + +/*****************************************************************************/ + +NM_GOBJECT_PROPERTIES_DEFINE(NMSettingHostname, + PROP_PRIORITY, + PROP_FROM_DHCP, + PROP_FROM_DNS_LOOKUP, + PROP_ONLY_FROM_DEFAULT, ); + +/** + * NMSettingHostname: + * + * Hostname settings + * + * Since: 1.30 + */ +struct _NMSettingHostname { + NMSetting parent; + int priority; + NMTernary from_dhcp; + NMTernary from_dns_lookup; + NMTernary only_from_default; +}; + +struct _NMSettingHostnameClass { + NMSettingClass parent; +}; + +G_DEFINE_TYPE(NMSettingHostname, nm_setting_hostname, NM_TYPE_SETTING) + +/** + * nm_setting_hostname_get_priority: + * @setting: the #NMSettingHostname + * + * Returns the value contained in the #NMSettingHostname:priority + * property. + * + * Returns: the 'priority' property value + * + * Since: 1.30 + **/ +int +nm_setting_hostname_get_priority(NMSettingHostname *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_HOSTNAME(setting), 0); + + return setting->priority; +} + +/** + * nm_setting_hostname_get_from_dhcp: + * @setting: the #NMSettingHostname + * + * Returns the value contained in the #NMSettingHostname:from-dhcp + * property. + * + * Returns: the 'from-dhcp' property value + * + * Since: 1.30 + **/ +NMTernary +nm_setting_hostname_get_from_dhcp(NMSettingHostname *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_HOSTNAME(setting), NM_TERNARY_DEFAULT); + + return setting->from_dhcp; +} + +/** + * nm_setting_hostname_get_from_dns_lookup: + * @setting: the #NMSettingHostname + * + * Returns the value contained in the #NMSettingHostname:from-dns-lookup + * property. + * + * Returns: the 'from-dns-lookup' property value + * + * Since: 1.30 + **/ +NMTernary +nm_setting_hostname_get_from_dns_lookup(NMSettingHostname *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_HOSTNAME(setting), NM_TERNARY_DEFAULT); + + return setting->from_dns_lookup; +} + +/** + * nm_setting_hostname_get_only_from_default: + * @setting: the #NMSettingHostname + * + * Returns the value contained in the #NMSettingHostname:only-from-default + * property. + * + * Returns: the 'only-from-default' property value + * + * Since: 1.30 + **/ +NMTernary +nm_setting_hostname_get_only_from_default(NMSettingHostname *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_HOSTNAME(setting), NM_TERNARY_DEFAULT); + + return setting->only_from_default; +} + +/*****************************************************************************/ + +static void +get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + NMSettingHostname *self = NM_SETTING_HOSTNAME(object); + + switch (prop_id) { + case PROP_PRIORITY: + g_value_set_int(value, self->priority); + break; + case PROP_FROM_DHCP: + g_value_set_enum(value, self->from_dhcp); + break; + case PROP_FROM_DNS_LOOKUP: + g_value_set_enum(value, self->from_dns_lookup); + break; + case PROP_ONLY_FROM_DEFAULT: + g_value_set_enum(value, self->only_from_default); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + NMSettingHostname *self = NM_SETTING_HOSTNAME(object); + + switch (prop_id) { + case PROP_PRIORITY: + self->priority = g_value_get_int(value); + break; + case PROP_FROM_DHCP: + self->from_dhcp = g_value_get_enum(value); + break; + case PROP_FROM_DNS_LOOKUP: + self->from_dns_lookup = g_value_get_enum(value); + break; + case PROP_ONLY_FROM_DEFAULT: + self->only_from_default = g_value_get_enum(value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +/*****************************************************************************/ + +static void +nm_setting_hostname_init(NMSettingHostname *setting) +{ + setting->from_dhcp = NM_TERNARY_DEFAULT; + setting->from_dns_lookup = NM_TERNARY_DEFAULT; + setting->only_from_default = NM_TERNARY_DEFAULT; +} + +/** + * nm_setting_hostname_new: + * + * Creates a new #NMSettingHostname object with default values. + * + * Returns: (transfer full): the new empty #NMSettingHostname object + * + * Since: 1.30 + **/ +NMSetting * +nm_setting_hostname_new(void) +{ + return g_object_new(NM_TYPE_SETTING_HOSTNAME, NULL); +} + +static void +nm_setting_hostname_class_init(NMSettingHostnameClass *klass) +{ + GObjectClass * object_class = G_OBJECT_CLASS(klass); + NMSettingClass *setting_class = NM_SETTING_CLASS(klass); + + object_class->get_property = get_property; + object_class->set_property = set_property; + + /** + * NMSettingHostname:priority + * + * The relative priority of this connection to determine the + * system hostname. A lower numerical value is better (higher + * priority). A connection with higher priority is considered + * before connections with lower priority. + * + * If the value is zero, it can be overridden by a global value + * from NetworkManager configuration. If the property doesn't have + * a value in the global configuration, the value is assumed to be + * 100. + * + * Negative values have the special effect of excluding other + * connections with a greater numerical priority value; so in + * presence of at least one negative priority, only connections + * with the lowest priority value will be used to determine the + * hostname. + * + * Since: 1.30 + **/ + /* ---ifcfg-rh--- + * property: priority + * variable: HOSTNAME_PRIORITY(+) + * default: missing variable means global value or 100 + * description: hostname priority + * example: HOSTNAME_PRIORITY=50 + * ---end--- + */ + obj_properties[PROP_PRIORITY] = g_param_spec_int(NM_SETTING_HOSTNAME_PRIORITY, + "", + "", + G_MININT32, + G_MAXINT32, + 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + /** + * NMSettingHostname:from-dhcp + * + * Whether the system hostname can be determined from DHCP on + * this connection. + * + * When set to %NM_TERNARY_DEFAULT, the value from global configuration + * is used. If the property doesn't have a value in the global + * configuration, NetworkManager assumes the value to be %NM_TERNARY_TRUE. + * + * Since: 1.30 + **/ + /* ---ifcfg-rh--- + * property: from-dhcp + * variable: HOSTNAME_FROM_DHCP(+) + * default: missing variable means global default or 1 + * description: whether the system hostname can be determined from DHCP + * example: HOSTNAME_FROM_DHCP=0,1 + * ---end--- + */ + obj_properties[PROP_FROM_DHCP] = g_param_spec_enum( + NM_SETTING_HOSTNAME_FROM_DHCP, + "", + "", + NM_TYPE_TERNARY, + NM_TERNARY_DEFAULT, + NM_SETTING_PARAM_FUZZY_IGNORE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + /** + * NMSettingHostname:from-dns-lookup + * + * Whether the system hostname can be determined from reverse + * DNS lookup of addresses on this device. + * + * When set to %NM_TERNARY_DEFAULT, the value from global configuration + * is used. If the property doesn't have a value in the global + * configuration, NetworkManager assumes the value to be %NM_TERNARY_TRUE. + * + * Since: 1.30 + **/ + /* ---ifcfg-rh--- + * property: from-dhcp + * variable: HOSTNAME_FROM_DNS_LOOKUP(+) + * default: missing variable means global default or 1 + * description: whether the system hostname can be determined from reverse + * DNS lookup + * example: HOSTNAME_FROM_DNS_LOOKUP=0,1 + * ---end--- + */ + obj_properties[PROP_FROM_DNS_LOOKUP] = g_param_spec_enum( + NM_SETTING_HOSTNAME_FROM_DNS_LOOKUP, + "", + "", + NM_TYPE_TERNARY, + NM_TERNARY_DEFAULT, + NM_SETTING_PARAM_FUZZY_IGNORE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + /** + * NMSettingHostname:only-from-default + * + * If set to %NM_TERNARY_TRUE, NetworkManager attempts to get + * the hostname via DHCPv4/DHCPv6 or reverse DNS lookup on this + * device only when the device has the default route for the given + * address family (IPv4/IPv6). + * + * If set to %NM_TERNARY_FALSE, the hostname can be set from this + * device even if it doesn't have the default route. + * + * When set to %NM_TERNARY_DEFAULT, the value from global configuration + * is used. If the property doesn't have a value in the global + * configuration, NetworkManager assumes the value to be %NM_TERNARY_TRUE. + * + * Since: 1.30 + **/ + /* ---ifcfg-rh--- + * property: only-best-device + * variable: HOSTNAME_ONLY_FROM_DEFAULT(+) + * default: missing variable means global default or 1 + * description: whether the hostname can be determined only from + * devices with the default route + * example: HOSTNAME_ONLY_FROM_DEFAULT=0,1 + * ---end--- + */ + obj_properties[PROP_ONLY_FROM_DEFAULT] = g_param_spec_enum( + NM_SETTING_HOSTNAME_ONLY_FROM_DEFAULT, + "", + "", + NM_TYPE_TERNARY, + NM_TERNARY_DEFAULT, + NM_SETTING_PARAM_FUZZY_IGNORE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + _nm_setting_class_commit(setting_class, NM_META_SETTING_TYPE_HOSTNAME); +} diff --git a/libnm-core/nm-setting-hostname.h b/libnm-core/nm-setting-hostname.h new file mode 100644 index 0000000000..184d76c483 --- /dev/null +++ b/libnm-core/nm-setting-hostname.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +/* + * Copyright (C) 2020 Red Hat, Inc. + */ + +#ifndef NM_SETTING_HOSTNAME_H +#define NM_SETTING_HOSTNAME_H + +#if !defined(__NETWORKMANAGER_H_INSIDE__) && !defined(NETWORKMANAGER_COMPILATION) + #error "Only <NetworkManager.h> can be included directly." +#endif + +#include "nm-setting.h" + +G_BEGIN_DECLS + +#define NM_TYPE_SETTING_HOSTNAME (nm_setting_hostname_get_type()) +#define NM_SETTING_HOSTNAME(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_SETTING_HOSTNAME, NMSettingHostname)) +#define NM_SETTING_HOSTNAME_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_SETTING_HOSTNAME, NMSettingHostnameClass)) +#define NM_IS_SETTING_HOSTNAME(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_SETTING_HOSTNAME)) +#define NM_IS_SETTING_HOSTNAME_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_SETTING_HOSTNAME)) +#define NM_SETTING_HOSTNAME_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_SETTING_HOSTNAME, NMSettingHostnameClass)) + +#define NM_SETTING_HOSTNAME_SETTING_NAME "hostname" + +#define NM_SETTING_HOSTNAME_PRIORITY "priority" +#define NM_SETTING_HOSTNAME_FROM_DHCP "from-dhcp" +#define NM_SETTING_HOSTNAME_FROM_DNS_LOOKUP "from-dns-lookup" +#define NM_SETTING_HOSTNAME_ONLY_FROM_DEFAULT "only-from-default" + +typedef struct _NMSettingHostnameClass NMSettingHostnameClass; + +NM_AVAILABLE_IN_1_30 +GType nm_setting_hostname_get_type(void); +NM_AVAILABLE_IN_1_30 +NMSetting *nm_setting_hostname_new(void); + +NM_AVAILABLE_IN_1_30 +int nm_setting_hostname_get_priority(NMSettingHostname *setting); +NM_AVAILABLE_IN_1_30 +NMTernary nm_setting_hostname_get_from_dhcp(NMSettingHostname *setting); +NM_AVAILABLE_IN_1_30 +NMTernary nm_setting_hostname_get_from_dns_lookup(NMSettingHostname *setting); +NM_AVAILABLE_IN_1_30 +NMTernary nm_setting_hostname_get_only_from_default(NMSettingHostname *setting); + +G_END_DECLS + +#endif /* NM_SETTING_HOSTNAME_H */ diff --git a/libnm/NetworkManager.h b/libnm/NetworkManager.h index 9193a08a0f..6864f7e84c 100644 --- a/libnm/NetworkManager.h +++ b/libnm/NetworkManager.h @@ -62,6 +62,7 @@ #include "nm-setting-ethtool.h" #include "nm-setting-generic.h" #include "nm-setting-gsm.h" +#include "nm-setting-hostname.h" #include "nm-setting-infiniband.h" #include "nm-setting-ip4-config.h" #include "nm-setting-ip6-config.h" diff --git a/libnm/libnm.ver b/libnm/libnm.ver index 0086fc01d2..100b9b93ee 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1766,6 +1766,11 @@ global: nm_keyfile_read; nm_keyfile_warn_severity_get_type; nm_keyfile_write; + nm_setting_hostname_get_from_dhcp; + nm_setting_hostname_get_from_dns_lookup; + nm_setting_hostname_get_only_from_default; + nm_setting_hostname_get_priority; + nm_setting_hostname_get_type; nm_setting_ovs_external_ids_check_key; nm_setting_ovs_external_ids_check_val; nm_setting_ovs_external_ids_get_data; diff --git a/libnm/nm-client.c b/libnm/nm-client.c index e2052204cd..8eb1e3031c 100644 --- a/libnm/nm-client.c +++ b/libnm/nm-client.c @@ -1166,7 +1166,7 @@ nml_dbus_object_iface_data_get(NMLDBusObject *dbobj, count++; } } else { - nm_c_list_for_each_entry_prev (db_iface_data, &dbobj->iface_lst_head, iface_lst) { + c_list_for_each_entry_prev (db_iface_data, &dbobj->iface_lst_head, iface_lst) { if (db_iface_data->dbus_iface_is_wellknown) break; if (db_iface_data->iface_removed) diff --git a/man/NetworkManager.conf.xml b/man/NetworkManager.conf.xml index 6b573890f8..a235cf2553 100644 --- a/man/NetworkManager.conf.xml +++ b/man/NetworkManager.conf.xml @@ -278,18 +278,24 @@ no-auto-default=* this option. An hostname empty or equal to 'localhost', 'localhost6', 'localhost.localdomain' or 'localhost6.localdomain' is considered invalid. </para> - <para><literal>default</literal>: NetworkManager will update the hostname - with the one provided via DHCP on the main connection (the one with a default - route). If not present, the hostname will be updated to the last one set - outside NetworkManager. If it is not valid, NetworkManager will try to recover - the hostname from the reverse lookup of the IP address of the main connection. - If this fails too, the hostname will be set to 'localhost.localdomain'. + <para><literal>default</literal>: NetworkManager will update the + hostname with the one provided via DHCP or reverse DNS lookup of the + IP address on the connection with the default route or on any + connection with the property hostname.only-from-default set to + '<literal>false</literal>'. Connections are considered in order of + increasing value of the <literal>hostname.priority</literal> + property. In case multiple connections have the same priority, + connections activated earlier are considered first. If no hostname can + be determined in such way, the hostname will be updated to the last + one set outside NetworkManager or to 'localhost.localdomain'. </para> - <para><literal>dhcp</literal>: NetworkManager will update the transient hostname - only with information coming from DHCP. No fallback nor reverse lookup will be - performed, but when the dhcp connection providing the hostname is deactivated, - the hostname is reset to the last hostname set outside NetworkManager or - 'localhost' if none valid is there. + <para><literal>dhcp</literal>: this is similar to + '<literal>default</literal>', with the difference that after trying to + get the DHCP hostname, reverse DNS lookup is not done. Note that + selecting this option is equivalent to setting the property + '<literal>hostname.from-dns-lookup</literal>' to + '<literal>false</literal>' globally for all connections in + NetworkManager.conf. </para> <para><literal>none</literal>: NetworkManager will not manage the transient hostname and will never set it. @@ -735,6 +741,18 @@ ipv6.ip6-privacy=0 <term><varname>gsm.mtu</varname></term> </varlistentry> <varlistentry> + <term><varname>hostname.from-dhcp</varname></term> + </varlistentry> + <varlistentry> + <term><varname>hostname.from-dns-lookup</varname></term> + </varlistentry> + <varlistentry> + <term><varname>hostname.only-from-default</varname></term> + </varlistentry> + <varlistentry> + <term><varname>hostname.priority</varname></term> + </varlistentry> + <varlistentry> <term><varname>infiniband.mtu</varname></term> <listitem><para>If configured explicitly to 0, the MTU is not reconfigured during device activation unless it is required due to IPv6 constraints. If left unspecified, a DHCP/IPv6 SLAAC provided value is used or the MTU is left unspecified on activation.</para></listitem> </varlistentry> diff --git a/shared/nm-glib-aux/nm-c-list.h b/shared/nm-glib-aux/nm-c-list.h index e19774dd91..173861c63c 100644 --- a/shared/nm-glib-aux/nm-c-list.h +++ b/shared/nm-glib-aux/nm-c-list.h @@ -17,11 +17,6 @@ _what &&c_list_contains(list, &_what->member); \ }) -/* iterate over the list backwards. */ -#define nm_c_list_for_each_entry_prev(_iter, _list, _m) \ - for (_iter = c_list_entry((_list)->prev, __typeof__(*_iter), _m); &(_iter)->_m != (_list); \ - _iter = c_list_entry((_iter)->_m.prev, __typeof__(*_iter), _m)) - /*****************************************************************************/ typedef struct { diff --git a/shared/nm-meta-setting.c b/shared/nm-meta-setting.c index 5356b9a5de..c137e6208c 100644 --- a/shared/nm-meta-setting.c +++ b/shared/nm-meta-setting.c @@ -21,6 +21,7 @@ #include "nm-setting-ethtool.h" #include "nm-setting-generic.h" #include "nm-setting-gsm.h" +#include "nm-setting-hostname.h" #include "nm-setting-infiniband.h" #include "nm-setting-ip-config.h" #include "nm-setting-ip-tunnel.h" @@ -243,6 +244,13 @@ const NMMetaSettingInfo nm_meta_setting_infos[] = { .setting_name = NM_SETTING_GSM_SETTING_NAME, .get_setting_gtype = nm_setting_gsm_get_type, }, + [NM_META_SETTING_TYPE_HOSTNAME] = + { + .meta_type = NM_META_SETTING_TYPE_HOSTNAME, + .setting_priority = NM_SETTING_PRIORITY_IP, + .setting_name = NM_SETTING_HOSTNAME_SETTING_NAME, + .get_setting_gtype = nm_setting_hostname_get_type, + }, [NM_META_SETTING_TYPE_INFINIBAND] = { .meta_type = NM_META_SETTING_TYPE_INFINIBAND, diff --git a/shared/nm-meta-setting.h b/shared/nm-meta-setting.h index 9d268e0ec2..c1023fb5ab 100644 --- a/shared/nm-meta-setting.h +++ b/shared/nm-meta-setting.h @@ -119,6 +119,7 @@ typedef enum { NM_META_SETTING_TYPE_ETHTOOL, NM_META_SETTING_TYPE_GENERIC, NM_META_SETTING_TYPE_GSM, + NM_META_SETTING_TYPE_HOSTNAME, NM_META_SETTING_TYPE_INFINIBAND, NM_META_SETTING_TYPE_IP_TUNNEL, NM_META_SETTING_TYPE_IP4_CONFIG, diff --git a/shared/nm-std-aux/c-list-util.h b/shared/nm-std-aux/c-list-util.h index 828481e114..8f40d32133 100644 --- a/shared/nm-std-aux/c-list-util.h +++ b/shared/nm-std-aux/c-list-util.h @@ -42,4 +42,15 @@ c_list_length_is(const CList *list, unsigned long check_len) return n == check_len; } +#define c_list_for_each_prev(_iter, _list) \ + for (_iter = (_list)->prev; (_iter) != (_list); _iter = (_iter)->prev) + +#define c_list_for_each_prev_safe(_iter, _safe, _list) \ + for (_iter = (_list)->prev, _safe = (_iter)->prev; (_iter) != (_list); \ + _iter = (_safe), _safe = (_safe)->prev) + +#define c_list_for_each_entry_prev(_iter, _list, _m) \ + for (_iter = c_list_entry((_list)->prev, __typeof__(*_iter), _m); &(_iter)->_m != (_list); \ + _iter = c_list_entry((_iter)->_m.prev, __typeof__(*_iter), _m)) + #endif /* __C_LIST_UTIL_H__ */ diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index b905855cf5..98b4d339e4 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -206,6 +206,23 @@ typedef struct { NMEthtoolRingState * ring; } EthtoolState; +typedef enum { + RESOLVER_WAIT_ADDRESS = 0, + RESOLVER_IN_PROGRESS, + RESOLVER_DONE, +} ResolverState; + +typedef struct { + ResolverState state; + GResolver * resolver; + GInetAddress *address; + GCancellable *cancellable; + char * hostname; + NMDevice * device; + guint timeout_id; /* Used when waiting for the address */ + int addr_family; +} HostnameResolver; + /*****************************************************************************/ enum { @@ -218,6 +235,7 @@ enum { REMOVED, RECHECK_AUTO_ACTIVATE, RECHECK_ASSUME, + DNS_LOOKUP_DONE, LAST_SIGNAL, }; static guint signals[LAST_SIGNAL] = {0}; @@ -325,6 +343,14 @@ typedef struct _NMDevicePrivate { int auth_retries; union { + struct { + HostnameResolver *hostname_resolver_6; + HostnameResolver *hostname_resolver_4; + }; + HostnameResolver *hostname_resolver_x[2]; + }; + + union { const guint8 hw_addr_len; /* read-only */ guint8 hw_addr_len_; }; @@ -866,6 +892,22 @@ static NM_UTILS_LOOKUP_STR_DEFINE(mtu_source_to_str, /*****************************************************************************/ +static void +_hostname_resolver_free(HostnameResolver *resolver) +{ + if (!resolver) + return; + + nm_clear_g_source(&resolver->timeout_id); + nm_clear_g_cancellable(&resolver->cancellable); + nm_g_object_unref(resolver->resolver); + nm_g_object_unref(resolver->address); + g_free(resolver->hostname); + nm_g_slice_free(resolver); +} + +/*****************************************************************************/ + static NMSettingIP6ConfigPrivacy _ip6_privacy_clamp(NMSettingIP6ConfigPrivacy use_tempaddr) { @@ -15618,6 +15660,7 @@ static void _cleanup_generic_pre(NMDevice *self, CleanupType cleanup_type) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + guint i; _cancel_activation(self); @@ -15642,6 +15685,9 @@ _cleanup_generic_pre(NMDevice *self, CleanupType cleanup_type) nm_clear_pointer(&priv->shared_ip_handle, nm_netns_shared_ip_release); + for (i = 0; i < 2; i++) + nm_clear_pointer(&priv->hostname_resolver_x[i], _hostname_resolver_free); + _cleanup_ip_pre(self, AF_INET, cleanup_type); _cleanup_ip_pre(self, AF_INET6, cleanup_type); } @@ -17467,6 +17513,178 @@ nm_device_auth_retries_try_next(NMDevice *self) return TRUE; } +static void +hostname_dns_lookup_callback(GObject *source, GAsyncResult *result, gpointer user_data) +{ + HostnameResolver *resolver; + NMDevice * self; + gs_free char * hostname = NULL; + gs_free char * addr_str = NULL; + gs_free_error GError *error = NULL; + + hostname = g_resolver_lookup_by_address_finish(G_RESOLVER(source), result, &error); + if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + resolver = user_data; + self = resolver->device; + resolver->state = RESOLVER_DONE; + resolver->hostname = g_strdup(hostname); + + _LOGD(LOGD_DNS, + "hostname-from-dns: lookup done for %s, result %s%s%s", + (addr_str = g_inet_address_to_string(resolver->address)), + NM_PRINT_FMT_QUOTE_STRING(hostname)); + + nm_clear_g_cancellable(&resolver->cancellable); + g_signal_emit(self, signals[DNS_LOOKUP_DONE], 0); +} + +static gboolean +hostname_dns_address_timeout(gpointer user_data) +{ + HostnameResolver *resolver = user_data; + NMDevice * self = resolver->device; + + g_return_val_if_fail(NM_IS_DEVICE(self), G_SOURCE_REMOVE); + + nm_assert(resolver->state == RESOLVER_WAIT_ADDRESS); + nm_assert(!resolver->address); + nm_assert(!resolver->cancellable); + + _LOGT(LOGD_DNS, + "hostname-from-dns: timed out while waiting IPv%c address", + nm_utils_addr_family_to_char(resolver->addr_family)); + + resolver->timeout_id = 0; + resolver->state = RESOLVER_DONE; + g_signal_emit(self, signals[DNS_LOOKUP_DONE], 0); + + return G_SOURCE_REMOVE; +} + +/* return value is valid only immediately */ +const char * +nm_device_get_hostname_from_dns_lookup(NMDevice *self, int addr_family, gboolean *out_wait) +{ + NMDevicePrivate * priv; + const int IS_IPv4 = NM_IS_IPv4(addr_family); + HostnameResolver *resolver; + NMIPConfig * ip_config; + const char * method; + gboolean address_changed = FALSE; + gs_unref_object GInetAddress *new_address = NULL; + + g_return_val_if_fail(NM_IS_DEVICE(self), NULL); + priv = NM_DEVICE_GET_PRIVATE(self); + + /* If the device is not supposed to have addresses, + * return an immediate empty result.*/ + method = nm_device_get_effective_ip_config_method(self, addr_family); + if (IS_IPv4) { + if (NM_IN_STRSET(method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) { + nm_clear_pointer(&priv->hostname_resolver_x[IS_IPv4], _hostname_resolver_free); + NM_SET_OUT(out_wait, FALSE); + return NULL; + } + } else { + if (NM_IN_STRSET(method, + NM_SETTING_IP6_CONFIG_METHOD_DISABLED, + NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { + nm_clear_pointer(&priv->hostname_resolver_x[IS_IPv4], _hostname_resolver_free); + NM_SET_OUT(out_wait, FALSE); + return NULL; + } + } + + resolver = priv->hostname_resolver_x[IS_IPv4]; + if (!resolver) { + resolver = g_slice_new(HostnameResolver); + *resolver = (HostnameResolver){ + .resolver = g_resolver_get_default(), + .device = self, + .addr_family = addr_family, + .state = RESOLVER_WAIT_ADDRESS, + }; + priv->hostname_resolver_x[IS_IPv4] = resolver; + } + + /* Determine the first address of the interface and + * whether it changed from the previous lookup */ + ip_config = priv->ip_config_x[IS_IPv4]; + if (ip_config) { + const NMPlatformIPAddress *addr; + + addr = nm_ip_config_get_first_address(ip_config); + if (addr) { + new_address = g_inet_address_new_from_bytes(addr->address_ptr, + IS_IPv4 ? G_SOCKET_FAMILY_IPV4 + : G_SOCKET_FAMILY_IPV6); + } + } + + if (new_address && resolver->address) { + if (!g_inet_address_equal(new_address, resolver->address)) + address_changed = TRUE; + } else if (new_address != resolver->address) + address_changed = TRUE; + + { + gs_free char *old_str = NULL; + gs_free char *new_str = NULL; + + _LOGT(LOGD_DNS, + "hostname-from-dns: ipv%c resolver state %d, old address %s, new address %s", + nm_utils_addr_family_to_char(resolver->addr_family), + resolver->state, + resolver->address ? (old_str = g_inet_address_to_string(resolver->address)) + : "(null)", + new_address ? (new_str = g_inet_address_to_string(new_address)) : "(null)"); + } + + /* In every state, if the address changed, we restart + * the resolution with the new address */ + if (address_changed) { + nm_clear_g_cancellable(&resolver->cancellable); + nm_g_object_unref(resolver->address); + resolver->state = RESOLVER_WAIT_ADDRESS; + } + + if (address_changed && new_address) { + gs_free char *str = NULL; + + _LOGT(LOGD_DNS, + "hostname-from-dns: starting lookup for address %s", + (str = g_inet_address_to_string(new_address))); + + resolver->state = RESOLVER_IN_PROGRESS; + resolver->cancellable = g_cancellable_new(); + resolver->address = g_steal_pointer(&new_address); + g_resolver_lookup_by_address_async(resolver->resolver, + resolver->address, + resolver->cancellable, + hostname_dns_lookup_callback, + resolver); + nm_clear_g_source(&resolver->timeout_id); + } + + switch (resolver->state) { + case RESOLVER_WAIT_ADDRESS: + if (!resolver->timeout_id) + resolver->timeout_id = g_timeout_add(30000, hostname_dns_address_timeout, resolver); + NM_SET_OUT(out_wait, TRUE); + return NULL; + case RESOLVER_IN_PROGRESS: + NM_SET_OUT(out_wait, TRUE); + return NULL; + case RESOLVER_DONE: + NM_SET_OUT(out_wait, FALSE); + return resolver->hostname; + } + + return nm_assert_unreachable_val(NULL); +} + /*****************************************************************************/ static const char * @@ -18644,6 +18862,16 @@ nm_device_class_init(NMDeviceClass *klass) NULL, G_TYPE_NONE, 0); + + signals[DNS_LOOKUP_DONE] = g_signal_new(NM_DEVICE_DNS_LOOKUP_DONE, + G_OBJECT_CLASS_TYPE(object_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 0); } /* Connection defaults from plugins */ diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index d29a6a1506..c330411bc4 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -116,6 +116,7 @@ nm_device_state_reason_check(NMDeviceStateReason reason) #define NM_DEVICE_HAS_PENDING_ACTION "has-pending-action" /* Internal only */ /* Internal signals */ +#define NM_DEVICE_DNS_LOOKUP_DONE "dns-lookup-done" #define NM_DEVICE_IP4_CONFIG_CHANGED "ip4-config-changed" #define NM_DEVICE_IP6_CONFIG_CHANGED "ip6-config-changed" #define NM_DEVICE_IP6_PREFIX_DELEGATED "ip6-prefix-delegated" @@ -863,4 +864,7 @@ const char *nm_device_state_reason_to_str(NMDeviceStateReason reason); gboolean nm_device_is_vpn(NMDevice *self); +const char * +nm_device_get_hostname_from_dns_lookup(NMDevice *self, int addr_family, gboolean *out_pending); + #endif /* __NETWORKMANAGER_DEVICE_H__ */ diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index ccfca74c1e..e1f231e527 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -369,6 +369,12 @@ nm_ip_config_hash(const NMIPConfig *self, GChecksum *sum, gboolean dns_only) _NM_IP_CONFIG_DISPATCH_VOID(self, nm_ip4_config_hash, nm_ip6_config_hash, sum, dns_only); } +static inline gconstpointer +nm_ip_config_get_first_address(NMIPConfig *self) +{ + _NM_IP_CONFIG_DISPATCH(self, nm_ip4_config_get_first_address, nm_ip6_config_get_first_address); +} + static inline void nm_ip_config_add_address(NMIPConfig *self, const NMPlatformIPAddress *address) { diff --git a/src/nm-manager.c b/src/nm-manager.c index 55680bef92..c17c881b68 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -142,7 +142,7 @@ typedef struct { GArray *capabilities; - CList active_connections_lst_head; + CList active_connections_lst_head; /* Oldest ACs at the beginning */ CList async_op_lst_head; guint ac_cleanup_id; NMActiveConnection *primary_connection; @@ -941,7 +941,7 @@ active_connection_add(NMManager *self, NMActiveConnection *active) nm_assert(NM_IS_ACTIVE_CONNECTION(active)); nm_assert(!c_list_is_linked(&active->active_connections_lst)); - c_list_link_front(&priv->active_connections_lst_head, &active->active_connections_lst); + c_list_link_tail(&priv->active_connections_lst_head, &active->active_connections_lst); g_object_ref(active); g_signal_connect(active, @@ -7867,7 +7867,9 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) break; case PROP_ACTIVE_CONNECTIONS: ptrarr = g_ptr_array_new(); - c_list_for_each_entry (ac, &priv->active_connections_lst_head, active_connections_lst) { + c_list_for_each_entry_prev (ac, + &priv->active_connections_lst_head, + active_connections_lst) { path = nm_dbus_object_get_path(NM_DBUS_OBJECT(ac)); if (path) g_ptr_array_add(ptrarr, g_strdup(path)); diff --git a/src/nm-manager.h b/src/nm-manager.h index 75f8a673d0..fcb29cf562 100644 --- a/src/nm-manager.h +++ b/src/nm-manager.h @@ -72,6 +72,7 @@ NMState nm_manager_get_state(NMManager *manager); const CList *nm_manager_get_active_connections(NMManager *manager); +/* From least recently activated */ #define nm_manager_for_each_active_connection(manager, iter, tmp_list) \ for (tmp_list = nm_manager_get_active_connections(manager), \ iter = c_list_entry(tmp_list->next, NMActiveConnection, active_connections_lst); \ @@ -86,6 +87,22 @@ const CList *nm_manager_get_active_connections(NMManager *manager); NMActiveConnection, \ active_connections_lst)) +/* From most recently activated */ +#define nm_manager_for_each_active_connection_prev(manager, iter, tmp_list) \ + for (tmp_list = nm_manager_get_active_connections(manager), \ + iter = c_list_entry(tmp_list->prev, NMActiveConnection, active_connections_lst); \ + ({ \ + const gboolean _has_prev = (&iter->active_connections_lst != tmp_list); \ + \ + if (!_has_prev) \ + iter = NULL; \ + _has_prev; \ + }); \ + iter = c_list_entry(iter->active_connections_lst.prev, \ + NMActiveConnection, \ + active_connections_lst)) + +/* From least recently activated */ #define nm_manager_for_each_active_connection_safe(manager, iter, tmp_list, iter_safe) \ for (tmp_list = nm_manager_get_active_connections(manager), iter_safe = tmp_list->next; ({ \ if (iter_safe != tmp_list) { \ diff --git a/src/nm-policy.c b/src/nm-policy.c index 60f5fb024b..bf54ede1a2 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -117,6 +117,8 @@ _PRIV_TO_SELF(NMPolicyPrivate *priv) /*****************************************************************************/ #define _NMLOG_PREFIX_NAME "policy" +#undef _NMLOG_ENABLED +#define _NMLOG_ENABLED(level, domain) (nm_logging_enabled((level), (domain))) #define _NMLOG(level, domain, ...) \ G_STMT_START \ { \ @@ -131,6 +133,7 @@ _PRIV_TO_SELF(NMPolicyPrivate *priv) /*****************************************************************************/ +static void update_system_hostname(NMPolicy *self, const char *msg); static void schedule_activate_all(NMPolicy *self); static void schedule_activate_check(NMPolicy *self, NMDevice *device); static NMDevice *get_default_device(NMPolicy *self, int addr_family); @@ -354,11 +357,11 @@ device_ip6_prefix_delegated(NMDevice *device, NMPlatformIP6Address *prefix, gpoi delegation->device = device; delegation->prefix = *prefix; - /* The newly activated connections are added to the list beginning, - * so traversing it from the beginning makes it likely for newly + /* The newly activated connections are added to the end of the list, + * so traversing it from the end makes it likely for newly * activated connections that have no subnet assigned to be served * first. That is a simple yet fair policy, which is good. */ - nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { + nm_manager_for_each_active_connection_prev (priv->manager, ac, tmp_list) { NMDevice *to_device; to_device = nm_active_connection_get_device(ac); @@ -671,20 +674,168 @@ lookup_by_address(NMPolicy *self) self); } +typedef struct { + NMDevice *device; + int priority; + bool from_dhcp : 1; + bool from_dns : 1; + + union { + struct { + bool ip_6; + bool ip_4; + }; + bool ip_x[2]; + }; +} DeviceHostnameInfo; + +static int +device_hostname_info_compare(gconstpointer a, gconstpointer b) +{ + const DeviceHostnameInfo *info1 = a; + const DeviceHostnameInfo *info2 = b; + + NM_CMP_FIELD(info1, info2, priority); + + return 0; +} + +NM_CON_DEFAULT_NOP("hostname.from-dhcp"); +NM_CON_DEFAULT_NOP("hostname.from-dns-lookup"); +NM_CON_DEFAULT_NOP("hostname.only-from-default"); + +static gboolean +device_get_hostname_property_boolean(NMDevice *device, const char *name) +{ + NMSettingHostname *s_hostname; + char buf[128]; + int value; + + nm_assert(NM_IN_STRSET(name, + NM_SETTING_HOSTNAME_FROM_DHCP, + NM_SETTING_HOSTNAME_FROM_DNS_LOOKUP, + NM_SETTING_HOSTNAME_ONLY_FROM_DEFAULT)); + + s_hostname = nm_device_get_applied_setting(device, NM_TYPE_SETTING_HOSTNAME); + + if (s_hostname) { + g_object_get(s_hostname, name, &value, NULL); + if (NM_IN_SET(value, NM_TERNARY_FALSE, NM_TERNARY_TRUE)) + return value; + } + + return nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, + nm_sprintf_buf(buf, "hostname.%s", name), + device, + NM_TERNARY_FALSE, + NM_TERNARY_TRUE, + NM_TERNARY_TRUE); +} + +static int +device_get_hostname_priority(NMDevice *device) +{ + NMSettingHostname *s_hostname; + int priority; + + s_hostname = nm_device_get_applied_setting(device, NM_TYPE_SETTING_HOSTNAME); + if (s_hostname) { + priority = nm_setting_hostname_get_priority(s_hostname); + if (priority != 0) + return priority; + } + + return nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, + NM_CON_DEFAULT("hostname.priority"), + device, + G_MININT, + G_MAXINT, + 100); +} + +static GArray * +build_device_hostname_infos(NMPolicy *self) +{ + NMPolicyPrivate * priv = NM_POLICY_GET_PRIVATE(self); + const CList * tmp_clist; + NMActiveConnection *ac; + GArray * array = NULL; + + nm_manager_for_each_active_connection (priv->manager, ac, tmp_clist) { + DeviceHostnameInfo *info; + NMDevice * device; + gboolean only_from_default; + + device = nm_active_connection_get_device(ac); + if (!device) + continue; + + only_from_default = + device_get_hostname_property_boolean(device, NM_SETTING_HOSTNAME_ONLY_FROM_DEFAULT); + if (only_from_default && ac != priv->default_ac4 && ac != priv->default_ac6) + continue; + + if (!array) + array = g_array_sized_new(FALSE, FALSE, sizeof(DeviceHostnameInfo), 4); + + info = nm_g_array_append_new(array, DeviceHostnameInfo); + *info = (DeviceHostnameInfo){ + .device = device, + .priority = device_get_hostname_priority(device), + .from_dhcp = + device_get_hostname_property_boolean(device, NM_SETTING_HOSTNAME_FROM_DHCP), + .from_dns = + device_get_hostname_property_boolean(device, NM_SETTING_HOSTNAME_FROM_DNS_LOOKUP), + .ip_4 = priv->default_ac4 || !only_from_default, + .ip_6 = priv->default_ac6 || !only_from_default, + }; + } + + if (array && array->len > 1) { + const DeviceHostnameInfo *info0; + guint i; + + g_array_sort(array, device_hostname_info_compare); + + info0 = &g_array_index(array, DeviceHostnameInfo, 0); + if (info0->priority < 0) { + for (i = 1; i < array->len; i++) { + const DeviceHostnameInfo *info = &g_array_index(array, DeviceHostnameInfo, i); + + if (info->priority > info0->priority) { + g_array_set_size(array, i); + break; + } + } + } + } + + return array; +} + +static void +device_dns_lookup_done(NMDevice *device, gpointer user_data) +{ + NMPolicy *self = user_data; + + g_signal_handlers_disconnect_by_func(device, device_dns_lookup_done, self); + + update_system_hostname(self, "lookup finished"); +} + static void update_system_hostname(NMPolicy *self, const char *msg) { - NMPolicyPrivate * priv = NM_POLICY_GET_PRIVATE(self); - const char * configured_hostname; - gs_free char * temp_hostname = NULL; - const char * dhcp_hostname, *p; - NMIP4Config * ip4_config; - NMIP6Config * ip6_config; - gboolean external_hostname = FALSE; - const NMPlatformIP4Address *addr4; - const NMPlatformIP6Address *addr6; - NMDevice * device; - NMDhcpConfig * dhcp_config; + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE(self); + const char * configured_hostname; + gs_free char * temp_hostname = NULL; + const char * dhcp_hostname, *p; + gboolean external_hostname = FALSE; + NMDhcpConfig * dhcp_config; + gs_unref_array GArray *infos = NULL; + DeviceHostnameInfo * info; + guint i; + int IS_IPv4; g_return_if_fail(self != NULL); @@ -724,10 +875,9 @@ update_system_hostname(NMPolicy *self, const char *msg) /* Hostname precedence order: * * 1) a configured hostname (from settings) - * 2) automatic hostname from the default device's config (DHCP, VPN, etc) - * 3) the last hostname set outside NM - * 4) reverse-DNS of the best device's IPv4 address - * + * 2) automatic hostname from DHCP of eligible interfaces + * 3) reverse-DNS lookup of the first address on eligible interfaces + * 4) the last hostname set outside NM */ /* Try a persistent hostname first */ @@ -738,40 +888,73 @@ update_system_hostname(NMPolicy *self, const char *msg) return; } - if (priv->default_ac4) { - /* Grab a hostname out of the device's DHCP4 config */ - dhcp_config = nm_device_get_dhcp_config(get_default_device(self, AF_INET), AF_INET); - if (dhcp_config) { - dhcp_hostname = nm_dhcp_config_get_option(dhcp_config, "host_name"); - if (dhcp_hostname && dhcp_hostname[0]) { - p = nm_str_skip_leading_spaces(dhcp_hostname); - if (p[0]) { - _set_hostname(self, p, "from DHCPv4"); - priv->dhcp_hostname = TRUE; - return; + infos = build_device_hostname_infos(self); + + if (infos && _LOGT_ENABLED(LOGD_DNS)) { + _LOGT(LOGD_DNS, "device hostname info:"); + for (i = 0; i < infos->len; i++) { + info = &g_array_index(infos, DeviceHostnameInfo, i); + _LOGT(LOGD_DNS, + " - prio:%4d ipv:%c%c dhcp:%d dns:%d dev:%s", + info->priority, + info->ip_4 ? '4' : '-', + info->ip_6 ? '6' : '-', + info->from_dhcp, + info->from_dns, + nm_device_get_iface(info->device)); + } + } + + for (i = 0; infos && i < infos->len; i++) { + info = &g_array_index(infos, DeviceHostnameInfo, i); + g_signal_handlers_disconnect_by_func(info->device, device_dns_lookup_done, self); + for (IS_IPv4 = 1; IS_IPv4 >= 0; IS_IPv4--) { + const int addr_family = IS_IPv4 ? AF_INET : AF_INET6; + + if (info->from_dhcp && info->ip_x[IS_IPv4]) { + dhcp_config = nm_device_get_dhcp_config(info->device, addr_family); + if (dhcp_config) { + dhcp_hostname = + nm_dhcp_config_get_option(dhcp_config, IS_IPv4 ? "host_name" : "fqdn_fqdn"); + if (dhcp_hostname && dhcp_hostname[0]) { + p = nm_str_skip_leading_spaces(dhcp_hostname); + if (p[0]) { + _set_hostname(self, p, IS_IPv4 ? "from DHCPv4" : "from DHCPv6"); + priv->dhcp_hostname = TRUE; + return; + } + _LOGW(LOGD_DNS, + "set-hostname: DHCPv%c-provided hostname '%s' looks invalid; " + "ignoring it", + nm_utils_addr_family_to_char(addr_family), + dhcp_hostname); + } } - _LOGW(LOGD_DNS, - "set-hostname: DHCPv4-provided hostname '%s' looks invalid; ignoring it", - dhcp_hostname); } } - } - if (priv->default_ac6) { - /* Grab a hostname out of the device's DHCP6 config */ - dhcp_config = nm_device_get_dhcp_config(get_default_device(self, AF_INET6), AF_INET6); - if (dhcp_config) { - dhcp_hostname = nm_dhcp_config_get_option(dhcp_config, "fqdn_fqdn"); - if (dhcp_hostname && dhcp_hostname[0]) { - p = nm_str_skip_leading_spaces(dhcp_hostname); - if (p[0]) { - _set_hostname(self, p, "from DHCPv6"); - priv->dhcp_hostname = TRUE; - return; + if (priv->hostname_mode != NM_POLICY_HOSTNAME_MODE_DHCP) { + for (IS_IPv4 = 1; IS_IPv4 >= 0; IS_IPv4--) { + const int addr_family = IS_IPv4 ? AF_INET6 : AF_INET; + + if (info->from_dns && info->ip_x[IS_IPv4]) { + const char *result; + gboolean wait; + + result = + nm_device_get_hostname_from_dns_lookup(info->device, addr_family, &wait); + if (result) { + _set_hostname(self, result, "from address lookup"); + return; + } + if (wait) { + g_signal_connect(info->device, + NM_DEVICE_DNS_LOOKUP_DONE, + (GCallback) device_dns_lookup_done, + self); + return; + } } - _LOGW(LOGD_DNS, - "set-hostname: DHCPv6-provided hostname '%s' looks invalid; ignoring it", - dhcp_hostname); } } } @@ -795,14 +978,6 @@ update_system_hostname(NMPolicy *self, const char *msg) priv->dhcp_hostname = FALSE; - if (!priv->default_ac4 && !priv->default_ac6) { - /* No best device; fall back to the last hostname set externally - * to NM or if there wasn't one, 'localhost.localdomain' - */ - _set_hostname(self, priv->orig_hostname, "no default device"); - return; - } - /* If no automatically-configured hostname, try using the last hostname * set externally to NM */ @@ -811,30 +986,7 @@ update_system_hostname(NMPolicy *self, const char *msg) return; } - /* No configured hostname, no automatically determined hostname, and no - * bootup hostname. Start reverse DNS of the current IPv4 or IPv6 address. - */ - device = get_default_device(self, AF_INET); - ip4_config = device ? nm_device_get_ip4_config(device) : NULL; - - device = get_default_device(self, AF_INET6); - ip6_config = device ? nm_device_get_ip6_config(device) : NULL; - - if (ip4_config && (addr4 = nm_ip4_config_get_first_address(ip4_config))) { - g_clear_object(&priv->lookup.addr); - priv->lookup.addr = - g_inet_address_new_from_bytes((guint8 *) &addr4->address, G_SOCKET_FAMILY_IPV4); - } else if (ip6_config && (addr6 = nm_ip6_config_get_first_address(ip6_config))) { - g_clear_object(&priv->lookup.addr); - priv->lookup.addr = - g_inet_address_new_from_bytes((guint8 *) &addr6->address, G_SOCKET_FAMILY_IPV6); - } else { - /* No valid IP config; fall back to localhost.localdomain */ - _set_hostname(self, NULL, "no IP config"); - return; - } - - lookup_by_address(self); + _set_hostname(self, NULL, "no hostname found"); } static void @@ -1796,6 +1948,8 @@ device_state_changed(NMDevice * device, switch (new_state) { case NM_DEVICE_STATE_FAILED: + g_signal_handlers_disconnect_by_func(device, device_dns_lookup_done, self); + /* Mark the connection invalid if it failed during activation so that * it doesn't get automatically chosen over and over and over again. */ @@ -1934,6 +2088,8 @@ device_state_changed(NMDevice * device, ip6_remove_device_prefix_delegations(self, device); break; case NM_DEVICE_STATE_DISCONNECTED: + g_signal_handlers_disconnect_by_func(device, device_dns_lookup_done, self); + /* Reset retry counts for a device's connections when carrier on; if cable * was unplugged and plugged in again, we should try to reconnect. */ diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index 3389b2a0aa..9b7873c01b 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -2547,6 +2547,42 @@ make_ip6_setting(shvarFile *ifcfg, shvarFile *network_ifcfg, gboolean routes_rea } static NMSetting * +make_hostname_setting(shvarFile *ifcfg) +{ + NMSetting *setting; + NMTernary from_dhcp; + NMTernary from_dns_lookup; + NMTernary only_from_default; + int priority; + + priority = svGetValueInt64(ifcfg, "HOSTNAME_PRIORITY", 10, G_MININT32, G_MAXINT32, 0); + + from_dhcp = svGetValueTernary(ifcfg, "HOSTNAME_FROM_DHCP"); + from_dns_lookup = svGetValueTernary(ifcfg, "HOSTNAME_FROM_DNS_LOOKUP"); + only_from_default = svGetValueTernary(ifcfg, "HOSTNAME_ONLY_FROM_DEFAULT"); + + /* Create the setting when at least one key is not default*/ + if (priority == 0 && from_dhcp == NM_TERNARY_DEFAULT && from_dns_lookup == NM_TERNARY_DEFAULT + && only_from_default == NM_TERNARY_DEFAULT) + return NULL; + + setting = nm_setting_hostname_new(); + + g_object_set(setting, + NM_SETTING_HOSTNAME_PRIORITY, + priority, + NM_SETTING_HOSTNAME_FROM_DHCP, + from_dhcp, + NM_SETTING_HOSTNAME_FROM_DNS_LOOKUP, + from_dns_lookup, + NM_SETTING_HOSTNAME_ONLY_FROM_DEFAULT, + only_from_default, + NULL); + + return setting; +} + +static NMSetting * make_sriov_setting(shvarFile *ifcfg) { gs_unref_hashtable GHashTable *keys = NULL; @@ -2951,7 +2987,8 @@ make_dcb_setting(shvarFile *ifcfg, NMSetting **out_setting, GError **error) gboolean dcb_on; NMSettingDcbFlags flags = NM_SETTING_DCB_FLAG_NONE; - g_return_val_if_fail(out_setting != NULL, FALSE); + g_return_val_if_fail(out_setting, FALSE); + *out_setting = NULL; dcb_on = !!svGetValueBoolean(ifcfg, "DCB", FALSE); if (!dcb_on) @@ -6243,8 +6280,9 @@ connection_from_file_full(const char *filename, gs_unref_object NMConnection *connection = NULL; gs_free char * type = NULL; char * devtype, *bootproto; - NMSetting * s_ip4, *s_ip6, *s_tc, *s_proxy, *s_port, *s_dcb = NULL, *s_user; - NMSetting * s_sriov, *s_match; + NMSetting * setting; + NMSetting * s_ip4; + NMSetting * s_ip6; const char * ifcfg_name = NULL; gboolean has_ip4_defroute = FALSE; gboolean has_complex_routes_v4; @@ -6532,13 +6570,13 @@ connection_from_file_full(const char *filename, NM_SETTING_IP_CONFIG(s_ip4), NM_SETTING_IP_CONFIG(s_ip6)); - s_sriov = make_sriov_setting(main_ifcfg); - if (s_sriov) - nm_connection_add_setting(connection, s_sriov); + setting = make_sriov_setting(main_ifcfg); + if (setting) + nm_connection_add_setting(connection, setting); - s_tc = make_tc_setting(main_ifcfg); - if (s_tc) - nm_connection_add_setting(connection, s_tc); + setting = make_tc_setting(main_ifcfg); + if (setting) + nm_connection_add_setting(connection, setting); /* For backwards compatibility, if IPv4 is disabled or the * config fails for some reason, we read DOMAIN and put the @@ -6546,30 +6584,34 @@ connection_from_file_full(const char *filename, */ check_dns_search_domains(main_ifcfg, s_ip4, s_ip6); - s_proxy = make_proxy_setting(main_ifcfg); - if (s_proxy) - nm_connection_add_setting(connection, s_proxy); + setting = make_proxy_setting(main_ifcfg); + if (setting) + nm_connection_add_setting(connection, setting); + + setting = make_hostname_setting(main_ifcfg); + if (setting) + nm_connection_add_setting(connection, setting); - s_user = make_user_setting(main_ifcfg); - if (s_user) - nm_connection_add_setting(connection, s_user); + setting = make_user_setting(main_ifcfg); + if (setting) + nm_connection_add_setting(connection, setting); - s_match = make_match_setting(main_ifcfg); - if (s_match) - nm_connection_add_setting(connection, s_match); + setting = make_match_setting(main_ifcfg); + if (setting) + nm_connection_add_setting(connection, setting); - s_port = make_bridge_port_setting(main_ifcfg); - if (s_port) - nm_connection_add_setting(connection, s_port); + setting = make_bridge_port_setting(main_ifcfg); + if (setting) + nm_connection_add_setting(connection, setting); - s_port = make_team_port_setting(main_ifcfg); - if (s_port) - nm_connection_add_setting(connection, s_port); + setting = make_team_port_setting(main_ifcfg); + if (setting) + nm_connection_add_setting(connection, setting); - if (!make_dcb_setting(main_ifcfg, &s_dcb, error)) + if (!make_dcb_setting(main_ifcfg, &setting, error)) return NULL; - if (s_dcb) - nm_connection_add_setting(connection, s_dcb); + if (setting) + nm_connection_add_setting(connection, setting); if (!nm_connection_normalize(connection, NULL, NULL, error)) return NULL; diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c index 567dc8a847..0ebc085330 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c @@ -873,6 +873,10 @@ const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[] = { _KEY_TYPE("GATEWAY_PING_TIMEOUT", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("GENERATE_MAC_ADDRESS_MASK", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("GVRP", NMS_IFCFG_KEY_TYPE_IS_PLAIN), + _KEY_TYPE("HOSTNAME_FROM_DHCP", NMS_IFCFG_KEY_TYPE_IS_PLAIN), + _KEY_TYPE("HOSTNAME_FROM_DNS_LOOKUP", NMS_IFCFG_KEY_TYPE_IS_PLAIN), + _KEY_TYPE("HOSTNAME_ONLY_FROM_DEFAULT", NMS_IFCFG_KEY_TYPE_IS_PLAIN), + _KEY_TYPE("HOSTNAME_PRIORITY", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("HWADDR", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("HWADDR_BLACKLIST", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("IEEE_8021X_ALTSUBJECT_MATCHES", NMS_IFCFG_KEY_TYPE_IS_PLAIN), diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h index 16ea7f0f88..97111e76ea 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h @@ -33,7 +33,7 @@ typedef struct { NMSIfcfgKeyTypeFlags key_flags; } NMSIfcfgKeyTypeInfo; -extern const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[243]; +extern const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[247]; const NMSIfcfgKeyTypeInfo *nms_ifcfg_well_known_key_find_info(const char *key, gssize *out_idx); diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index 648846727f..ee78780282 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -1051,6 +1051,28 @@ write_infiniband_setting(NMConnection *connection, shvarFile *ifcfg, GError **er return TRUE; } +static void +write_hostname_setting(NMConnection *connection, shvarFile *ifcfg) +{ + NMSettingHostname *s_hostname; + NMTernary t; + + s_hostname = _nm_connection_get_setting(connection, NM_TYPE_SETTING_HOSTNAME); + if (!s_hostname) + return; + + svSetValueInt64(ifcfg, "HOSTNAME_PRIORITY", nm_setting_hostname_get_priority(s_hostname)); + + t = nm_setting_hostname_get_from_dhcp(s_hostname); + svSetValueInt64_cond(ifcfg, "HOSTNAME_FROM_DHCP", t != NM_TERNARY_DEFAULT, t); + + t = nm_setting_hostname_get_from_dns_lookup(s_hostname); + svSetValueInt64_cond(ifcfg, "HOSTNAME_FROM_DNS_LOOKUP", t != NM_TERNARY_DEFAULT, t); + + t = nm_setting_hostname_get_only_from_default(s_hostname); + svSetValueInt64_cond(ifcfg, "HOSTNAME_ONLY_FROM_DEFAULT", t != NM_TERNARY_DEFAULT, t); +} + static gboolean write_wired_setting(NMConnection *connection, shvarFile *ifcfg, GError **error) { @@ -3347,7 +3369,7 @@ do_write_construct(NMConnection * connection, return FALSE; write_match_setting(connection, ifcfg); - + write_hostname_setting(connection, ifcfg); write_sriov_setting(connection, ifcfg); if (!write_tc_setting(connection, ifcfg, error)) |