summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBeniamino Galvani <bgalvani@redhat.com>2020-11-16 17:04:54 +0100
committerBeniamino Galvani <bgalvani@redhat.com>2020-11-16 17:04:54 +0100
commit090c360ca40e9cc3435e493db186df6b3584b6bc (patch)
treeb325b2afdd838ce8090c15151d5e34d1c9e8b801
parent5b7ce438d9333b6add7b7924f9e2902d91dee335 (diff)
parent09c83871144a5154a0b3003b77fbbd69f2c758db (diff)
downloadNetworkManager-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
-rw-r--r--.clang-format5
-rw-r--r--Makefile.am2
-rw-r--r--clients/cli/connections.c3
-rw-r--r--clients/cli/generate-docs-nm-settings-nmcli.xml.in10
-rw-r--r--clients/common/nm-meta-setting-desc.c21
-rw-r--r--clients/common/settings-docs.h.in4
-rw-r--r--docs/libnm/libnm-docs.xml1
-rw-r--r--libnm-core/meson.build2
-rw-r--r--libnm-core/nm-core-internal.h1
-rw-r--r--libnm-core/nm-core-types.h1
-rw-r--r--libnm-core/nm-setting-hostname.c339
-rw-r--r--libnm-core/nm-setting-hostname.h53
-rw-r--r--libnm/NetworkManager.h1
-rw-r--r--libnm/libnm.ver5
-rw-r--r--libnm/nm-client.c2
-rw-r--r--man/NetworkManager.conf.xml40
-rw-r--r--shared/nm-glib-aux/nm-c-list.h5
-rw-r--r--shared/nm-meta-setting.c8
-rw-r--r--shared/nm-meta-setting.h1
-rw-r--r--shared/nm-std-aux/c-list-util.h11
-rw-r--r--src/devices/nm-device.c228
-rw-r--r--src/devices/nm-device.h4
-rw-r--r--src/nm-ip4-config.h6
-rw-r--r--src/nm-manager.c8
-rw-r--r--src/nm-manager.h17
-rw-r--r--src/nm-policy.c314
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c96
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c4
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h2
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c24
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&apos;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&apos;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&apos;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&apos;t have the default route. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn&apos;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))