dns: Add resolve-mode and certification-authority keys to global-dns

Resolve-mode allows user to specify way how the global-dns domains
and DNS connection information should be merged and used.

Certification-authority allows user to specify certification
authority that should be used to verify certificates of encrypted
DNS servers.
This commit is contained in:
Tomas Korbar
2025-01-08 11:21:46 +01:00
parent c9be26cf9a
commit c08ecfd5fe
6 changed files with 154 additions and 9 deletions

5
NEWS
View File

@@ -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 * The initrd-generator understands the "rd.net.dns" option to configure
global name servers. global name servers.
* Drop support for the "dhcpcanon" DHCP client. * 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 NetworkManager-1.50

View File

@@ -1547,6 +1547,29 @@ managed=1
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>resolve-mode</varname></term>
<listitem>
<para>
String indicating how DNS servers retrieved from global configuration and connections
should be used. <literal>backup</literal> - Indicates that they can be freely merged
and used for the same purposes. <literal>prefer</literal> - Forbids DNS servers
retrieved from connections to be used for general queries that are not subdomains of
domains set by connection. <literal>exclusive</literal> - Forbids use of connection
DNS servers for any query. Currently relevant only for Dnsconfd plugin.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>certification-authority</varname></term>
<listitem>
<para>
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.
</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
</para> </para>
</refsect1> </refsect1>

View File

@@ -46,11 +46,13 @@ struct _NMGlobalDnsDomain {
}; };
struct _NMGlobalDnsConfig { struct _NMGlobalDnsConfig {
char **searches; char **searches;
char **options; char **options;
GHashTable *domains; GHashTable *domains;
const char **domain_list; const char **domain_list;
gboolean internal; 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; 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 guint
nm_global_dns_config_get_num_domains(const NMGlobalDnsConfig *dns_config) 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); g_free(dns_config->domain_list);
if (dns_config->domains) if (dns_config->domains)
g_hash_table_unref(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); 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); 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 * static NMGlobalDnsConfig *
load_global_dns(GKeyFile *keyfile, gboolean internal) 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; int g, i, j, domain_prefix_len;
gboolean default_found = FALSE; gboolean default_found = FALSE;
char **strv; char **strv;
gs_free char *cert_authority = NULL;
gs_free char *resolve_mode = NULL;
NMDnsResolveMode parsed_resolve_mode;
if (internal) { if (internal) {
group = NM_CONFIG_KEYFILE_GROUP_INTERN_GLOBAL_DNS; 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)) if (!nm_config_keyfile_has_global_dns_config(keyfile, internal))
return NULL; 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, dns_config->domains = g_hash_table_new_full(nm_str_hash,
g_str_equal, g_str_equal,
g_free, 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)); 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}")); g_variant_builder_init(&domains_builder, G_VARIANT_TYPE("a{sv}"));
if (dns_config->domain_list) { if (dns_config->domain_list) {
for (i = 0; dns_config->domain_list[i]; i++) { 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; GVariantIter iter;
char **strv, *key; char **strv, *key;
int i, j; int i, j;
gs_free char *resolve_mode_buffer = NULL;
if (!G_VALUE_HOLDS_VARIANT(value)) { if (!G_VALUE_HOLDS_VARIANT(value)) {
g_set_error(error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, "invalid value type"); 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); 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); g_variant_unref(val);
} }

View File

@@ -120,6 +120,13 @@ typedef enum {
} NMConfigChangeFlags; } 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 _NMConfigDataClass NMConfigDataClass;
typedef struct _NMGlobalDnsConfig NMGlobalDnsConfig; 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_searches(const NMGlobalDnsConfig *dns_config);
const char *const *nm_global_dns_config_get_options(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); 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_get_domain(const NMGlobalDnsConfig *dns_config, guint i);
NMGlobalDnsDomain *nm_global_dns_config_lookup_domain(const NMGlobalDnsConfig *dns_config, NMGlobalDnsDomain *nm_global_dns_config_lookup_domain(const NMGlobalDnsConfig *dns_config,

View File

@@ -905,7 +905,9 @@ static const ConfigGroup config_groups[] = {
{ {
.group = NM_CONFIG_KEYFILE_GROUP_GLOBAL_DNS, .group = NM_CONFIG_KEYFILE_GROUP_GLOBAL_DNS,
.keys = NM_MAKE_STRV(NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_OPTIONS, .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, .group = NM_CONFIG_KEYFILE_GROUPPREFIX_GLOBAL_DNS_DOMAIN,

View File

@@ -55,8 +55,10 @@
#define NM_CONFIG_KEYFILE_KEY_IFUPDOWN_MANAGED "managed" #define NM_CONFIG_KEYFILE_KEY_IFUPDOWN_MANAGED "managed"
#define NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_SEARCHES "searches" #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_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_SERVERS "servers"
#define NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_DOMAIN_OPTIONS "options" #define NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_DOMAIN_OPTIONS "options"