diff --git a/NEWS b/NEWS
index 6f57b415d..6309d535a 100644
--- a/NEWS
+++ b/NEWS
@@ -32,6 +32,11 @@ USE AT YOUR OWN RISK. NOT RECOMMENDED FOR PRODUCTION USE!
* The initrd-generator understands the "rd.net.dns" option to configure
global name servers.
* Drop support for the "dhcpcanon" DHCP client.
+* global-dns configuration section now has 2 additional keys: "resolve-mode"
+ and "certification-authority".
+* Dnsconfd plugin can now be used for configuration of system-wide DNS
+ caching resolver. If dnsconfd plugin is enabled and ipvX.routed-dns is
+ set to -1 then adding routes is by default enabled.
=============================================
NetworkManager-1.50
diff --git a/man/NetworkManager.conf.xml b/man/NetworkManager.conf.xml
index 70ddea387..0363dd863 100644
--- a/man/NetworkManager.conf.xml
+++ b/man/NetworkManager.conf.xml
@@ -1547,6 +1547,29 @@ managed=1
+
+ resolve-mode
+
+
+ String indicating how DNS servers retrieved from global configuration and connections
+ should be used. backup - Indicates that they can be freely merged
+ and used for the same purposes. prefer - Forbids DNS servers
+ retrieved from connections to be used for general queries that are not subdomains of
+ domains set by connection. exclusive - Forbids use of connection
+ DNS servers for any query. Currently relevant only for Dnsconfd plugin.
+
+
+
+
+ certification-authority
+
+
+ String specifying absolute path to bundle of CA certificates that must be used for
+ validation of certificates presented by DNS servers when encrypted DNS is used.
+ Currently relevant only for Dnsconfd plugin.
+
+
+
diff --git a/src/core/nm-config-data.c b/src/core/nm-config-data.c
index e40492851..5a84a2c89 100644
--- a/src/core/nm-config-data.c
+++ b/src/core/nm-config-data.c
@@ -46,11 +46,13 @@ struct _NMGlobalDnsDomain {
};
struct _NMGlobalDnsConfig {
- char **searches;
- char **options;
- GHashTable *domains;
- const char **domain_list;
- gboolean internal;
+ char **searches;
+ char **options;
+ GHashTable *domains;
+ const char **domain_list;
+ gboolean internal;
+ char *cert_authority;
+ NMDnsResolveMode resolve_mode;
};
/*****************************************************************************/
@@ -955,6 +957,22 @@ nm_global_dns_config_get_options(const NMGlobalDnsConfig *dns_config)
return (const char *const *) dns_config->options;
}
+const char *
+nm_global_dns_config_get_certification_authority(const NMGlobalDnsConfig *dns_config)
+{
+ g_return_val_if_fail(dns_config, NULL);
+
+ return (const char *) dns_config->cert_authority;
+}
+
+guint
+nm_global_dns_config_get_resolve_mode(const NMGlobalDnsConfig *dns_config)
+{
+ g_return_val_if_fail(dns_config, 0);
+
+ return dns_config->resolve_mode;
+}
+
guint
nm_global_dns_config_get_num_domains(const NMGlobalDnsConfig *dns_config)
{
@@ -1155,6 +1173,9 @@ nm_global_dns_config_free(NMGlobalDnsConfig *dns_config)
g_free(dns_config->domain_list);
if (dns_config->domains)
g_hash_table_unref(dns_config->domains);
+ if (dns_config->cert_authority) {
+ g_free(dns_config->cert_authority);
+ }
g_free(dns_config);
}
}
@@ -1180,6 +1201,29 @@ global_dns_config_seal_domains(NMGlobalDnsConfig *dns_config)
dns_config->domain_list = nm_strdict_get_keys(dns_config->domains, TRUE, NULL);
}
+static const char *
+nm_dns_resolve_mode_to_string(const NMDnsResolveMode mode)
+{
+ const char *to_string[3] = {"backup", "prefer", "exclusive"};
+
+ nm_assert(mode < _NM_NUM_DNS_RESOLVE_MODES);
+
+ return to_string[mode];
+}
+
+static NMDnsResolveMode
+nm_dns_resolve_mode_from_string(const char *string)
+{
+ if (nm_streq0(string, "backup")) {
+ return NM_DNS_RESOLVE_MODE_BACKUP;
+ } else if (nm_streq0(string, "prefer")) {
+ return NM_DNS_RESOLVE_MODE_PREFER;
+ } else if (nm_streq0(string, "exclusive")) {
+ return NM_DNS_RESOLVE_MODE_EXCLUSIVE;
+ }
+ return _NM_NUM_DNS_RESOLVE_MODES;
+}
+
static NMGlobalDnsConfig *
load_global_dns(GKeyFile *keyfile, gboolean internal)
{
@@ -1189,6 +1233,9 @@ load_global_dns(GKeyFile *keyfile, gboolean internal)
int g, i, j, domain_prefix_len;
gboolean default_found = FALSE;
char **strv;
+ gs_free char *cert_authority = NULL;
+ gs_free char *resolve_mode = NULL;
+ NMDnsResolveMode parsed_resolve_mode;
if (internal) {
group = NM_CONFIG_KEYFILE_GROUP_INTERN_GLOBAL_DNS;
@@ -1202,7 +1249,31 @@ load_global_dns(GKeyFile *keyfile, gboolean internal)
if (!nm_config_keyfile_has_global_dns_config(keyfile, internal))
return NULL;
- dns_config = g_malloc0(sizeof(NMGlobalDnsConfig));
+ dns_config = g_malloc0(sizeof(NMGlobalDnsConfig));
+
+ cert_authority = g_key_file_get_string(keyfile,
+ group,
+ NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_CERTIFICATION_AUTHORITY,
+ NULL);
+ if (cert_authority) {
+ dns_config->cert_authority = g_steal_pointer(&cert_authority);
+ }
+
+ resolve_mode =
+ g_key_file_get_string(keyfile, group, NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_RESOLVE_MODE, NULL);
+
+ if (resolve_mode) {
+ parsed_resolve_mode = nm_dns_resolve_mode_from_string(resolve_mode);
+ if (parsed_resolve_mode == _NM_NUM_DNS_RESOLVE_MODES) {
+ nm_log_dbg(LOGD_CORE,
+ "%s global DNS configuration has invalid value '%s', assuming backup",
+ internal ? "internal" : "user",
+ NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_RESOLVE_MODE);
+ } else {
+ dns_config->resolve_mode = parsed_resolve_mode;
+ }
+ }
+
dns_config->domains = g_hash_table_new_full(nm_str_hash,
g_str_equal,
g_free,
@@ -1344,6 +1415,21 @@ nm_global_dns_config_to_dbus(const NMGlobalDnsConfig *dns_config, GValue *value)
g_variant_new_strv((const char *const *) dns_config->options, -1));
}
+ if (dns_config->cert_authority) {
+ g_variant_builder_add(&conf_builder,
+ "{sv}",
+ "certification-authority",
+ g_variant_new("s", dns_config->cert_authority));
+ }
+
+ if (dns_config->resolve_mode) {
+ g_variant_builder_add(
+ &conf_builder,
+ "{sv}",
+ "resolve-mode",
+ g_variant_new("s", nm_dns_resolve_mode_to_string(dns_config->resolve_mode)));
+ }
+
g_variant_builder_init(&domains_builder, G_VARIANT_TYPE("a{sv}"));
if (dns_config->domain_list) {
for (i = 0; dns_config->domain_list[i]; i++) {
@@ -1444,6 +1530,7 @@ nm_global_dns_config_from_dbus(const GValue *value, GError **error)
GVariantIter iter;
char **strv, *key;
int i, j;
+ gs_free char *resolve_mode_buffer = NULL;
if (!G_VALUE_HOLDS_VARIANT(value)) {
g_set_error(error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, "invalid value type");
@@ -1499,7 +1586,23 @@ nm_global_dns_config_from_dbus(const GValue *value, GError **error)
}
g_variant_unref(v);
}
+ } else if (nm_streq0(key, "resolve-mode")
+ && g_variant_is_of_type(val, G_VARIANT_TYPE("s"))) {
+ g_variant_get(val, "s", &resolve_mode_buffer);
+ dns_config->resolve_mode = nm_dns_resolve_mode_from_string(resolve_mode_buffer);
+ if (dns_config->resolve_mode == _NM_NUM_DNS_RESOLVE_MODES) {
+ g_set_error_literal(error,
+ NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_FAILED,
+ "Global DNS configuration contains invalid resolve-mode");
+ nm_global_dns_config_free(dns_config);
+ return NULL;
+ }
+ } else if (nm_streq0(key, "certification-authority")
+ && g_variant_is_of_type(val, G_VARIANT_TYPE("s"))) {
+ g_variant_get(val, "s", &dns_config->cert_authority);
}
+
g_variant_unref(val);
}
diff --git a/src/core/nm-config-data.h b/src/core/nm-config-data.h
index 1ea0ccf25..d764a7c45 100644
--- a/src/core/nm-config-data.h
+++ b/src/core/nm-config-data.h
@@ -120,6 +120,13 @@ typedef enum {
} NMConfigChangeFlags;
+typedef enum {
+ NM_DNS_RESOLVE_MODE_BACKUP = 0,
+ NM_DNS_RESOLVE_MODE_PREFER = 1,
+ NM_DNS_RESOLVE_MODE_EXCLUSIVE = 2,
+ _NM_NUM_DNS_RESOLVE_MODES = 3
+} NMDnsResolveMode;
+
typedef struct _NMConfigDataClass NMConfigDataClass;
typedef struct _NMGlobalDnsConfig NMGlobalDnsConfig;
@@ -269,6 +276,9 @@ GKeyFile *nm_config_data_clone_keyfile_intern(const NMConfigData *self);
const char *const *nm_global_dns_config_get_searches(const NMGlobalDnsConfig *dns_config);
const char *const *nm_global_dns_config_get_options(const NMGlobalDnsConfig *dns_config);
+const char *nm_global_dns_config_get_certification_authority(const NMGlobalDnsConfig *dns_config);
+guint nm_global_dns_config_get_resolve_mode(const NMGlobalDnsConfig *dns_config);
+
guint nm_global_dns_config_get_num_domains(const NMGlobalDnsConfig *dns_config);
NMGlobalDnsDomain *nm_global_dns_config_get_domain(const NMGlobalDnsConfig *dns_config, guint i);
NMGlobalDnsDomain *nm_global_dns_config_lookup_domain(const NMGlobalDnsConfig *dns_config,
diff --git a/src/core/nm-config.c b/src/core/nm-config.c
index c6dc78d88..a55d2d139 100644
--- a/src/core/nm-config.c
+++ b/src/core/nm-config.c
@@ -905,7 +905,9 @@ static const ConfigGroup config_groups[] = {
{
.group = NM_CONFIG_KEYFILE_GROUP_GLOBAL_DNS,
.keys = NM_MAKE_STRV(NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_OPTIONS,
- NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_SEARCHES, ),
+ NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_SEARCHES,
+ NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_CERTIFICATION_AUTHORITY,
+ NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_RESOLVE_MODE, ),
},
{
.group = NM_CONFIG_KEYFILE_GROUPPREFIX_GLOBAL_DNS_DOMAIN,
diff --git a/src/libnm-base/nm-config-base.h b/src/libnm-base/nm-config-base.h
index 362a183c9..d101c95c8 100644
--- a/src/libnm-base/nm-config-base.h
+++ b/src/libnm-base/nm-config-base.h
@@ -55,8 +55,10 @@
#define NM_CONFIG_KEYFILE_KEY_IFUPDOWN_MANAGED "managed"
-#define NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_SEARCHES "searches"
-#define NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_OPTIONS "options"
+#define NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_SEARCHES "searches"
+#define NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_OPTIONS "options"
+#define NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_CERTIFICATION_AUTHORITY "certification-authority"
+#define NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_RESOLVE_MODE "resolve-mode"
#define NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_DOMAIN_SERVERS "servers"
#define NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_DOMAIN_OPTIONS "options"