merge: branch 'dns-hashes'

Refactor dns-manager to isolate resolvconf operations and allow plugins to implement their own checksum

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2215
This commit is contained in:
TomasKorbar 2026-04-16 12:57:49 +00:00
commit d04fc18054
15 changed files with 1918 additions and 1334 deletions

View file

@ -679,11 +679,7 @@ parse_all_interface_config(GVariantBuilder *argument_builder,
}
static gboolean
update(NMDnsPlugin *plugin,
const NMGlobalDnsConfig *global_config,
const CList *ip_data_lst_head,
const char *hostdomain,
GError **error)
update(NMDnsPlugin *plugin, NMDnsUpdateData *update_data, GError **error)
{
NMDnsDnsconfd *self = NM_DNS_DNSCONFD(plugin);
NMDnsDnsconfdPrivate *priv = NM_DNS_DNSCONFD_GET_PRIVATE(self);
@ -698,12 +694,12 @@ update(NMDnsPlugin *plugin,
g_variant_builder_init(&argument_builder, G_VARIANT_TYPE("(aa{sv}u)"));
g_variant_builder_open(&argument_builder, G_VARIANT_TYPE("aa{sv}"));
if (global_config) {
if (update_data->global_config) {
_LOGT("parsing global configuration");
parse_global_config(global_config, &argument_builder, &resolve_mode, &ca);
parse_global_config(update_data->global_config, &argument_builder, &resolve_mode, &ca);
}
_LOGT("parsing configuration of interfaces");
parse_all_interface_config(&argument_builder, ip_data_lst_head, ca);
parse_all_interface_config(&argument_builder, update_data->ip_data_lst_head, ca);
g_variant_builder_close(&argument_builder);
g_variant_builder_add(&argument_builder, "u", resolve_mode);
@ -812,6 +808,77 @@ dispose(GObject *object)
g_clear_object(&priv->dbus_connection);
}
static void
dnsconfd_checksum(const NML3ConfigData *l3cd,
GChecksum *sum,
int addr_family,
NMDnsIPConfigType dns_ip_config_type)
{
guint i;
NMDedupMultiIter ipconf_iter;
const NMPObject *obj;
const NMPlatformIPRoute *route;
const char *const *strarr;
const in_addr_t *wins;
guint element_num;
int prio = 0;
gboolean empty = TRUE;
g_return_if_fail(l3cd);
g_return_if_fail(sum);
strarr = nm_l3_config_data_get_nameservers(l3cd, addr_family, &element_num);
for (i = 0; i < element_num; i++) {
g_checksum_update(sum, (gpointer) strarr[i], strlen(strarr[i]));
empty = FALSE;
}
if (addr_family == AF_INET) {
wins = nm_l3_config_data_get_wins(l3cd, &element_num);
for (i = 0; i < element_num; i++) {
g_checksum_update(sum, (guint8 *) &wins[i], 4);
empty = FALSE;
}
}
/* Without servers, the sum should be zero, as Dnsconfd API is oriented
* around servers */
if (empty) {
_LOGT("no servers, thus checksum is zero");
return;
}
strarr = nm_l3_config_data_get_searches(l3cd, addr_family, &element_num);
for (i = 0; i < element_num; i++) {
g_checksum_update(sum, (const guint8 *) strarr[i], strlen(strarr[i]));
}
/* If we've got searches, then we do not care about domains, because
* searches have higher priority */
if (!element_num) {
strarr = nm_l3_config_data_get_domains(l3cd, addr_family, &element_num);
for (i = 0; i < element_num; i++) {
g_checksum_update(sum, (const guint8 *) strarr[i], strlen(strarr[i]));
}
}
nm_l3_config_data_iter_obj_for_each (&ipconf_iter,
l3cd,
&obj,
NMP_OBJECT_TYPE_IP_ROUTE(NM_IS_IPv4(addr_family))) {
route = NMP_OBJECT_CAST_IP_ROUTE(obj);
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT(route)
|| route->table_coerced == NM_DNS_ROUTES_FWMARK_TABLE_PRIO) {
continue;
}
g_checksum_update(sum, (const guint8 *) route, sizeof(*route));
}
g_checksum_update(sum, (const guint8 *) &dns_ip_config_type, sizeof(dns_ip_config_type));
nm_l3_config_data_get_dns_priority(l3cd, addr_family, &prio);
g_checksum_update(sum, (const guint8 *) &prio, sizeof(prio));
}
static void
nm_dns_dnsconfd_class_init(NMDnsDnsconfdClass *dns_class)
{
@ -825,4 +892,5 @@ nm_dns_dnsconfd_class_init(NMDnsDnsconfdClass *dns_class)
plugin_class->stop = stop;
plugin_class->update = update;
plugin_class->get_update_pending = get_update_pending;
plugin_class->checksum = dnsconfd_checksum;
}

View file

@ -22,6 +22,7 @@
#include "nm-dbus-manager.h"
#include "NetworkManagerUtils.h"
#include "nm-l3-config-data.h"
#include "nm-l3cfg.h"
#define PIDFILE NMRUNDIR "/dnsmasq.pid"
#define CONFDIR NMCONFDIR "/dnsmasq.d"
@ -1207,11 +1208,7 @@ start_dnsmasq(NMDnsDnsmasq *self, gboolean force_start, GError **error)
}
static gboolean
update(NMDnsPlugin *plugin,
const NMGlobalDnsConfig *global_config,
const CList *ip_data_lst_head,
const char *hostdomain,
GError **error)
update(NMDnsPlugin *plugin, NMDnsUpdateData *update_data, GError **error)
{
NMDnsDnsmasq *self = NM_DNS_DNSMASQ(plugin);
NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE(self);
@ -1220,8 +1217,10 @@ update(NMDnsPlugin *plugin,
return FALSE;
nm_clear_pointer(&priv->set_server_ex_args, g_variant_unref);
priv->set_server_ex_args =
g_variant_ref_sink(create_update_args(self, global_config, ip_data_lst_head, hostdomain));
priv->set_server_ex_args = g_variant_ref_sink(create_update_args(self,
update_data->global_config,
update_data->ip_data_lst_head,
update_data->hostdomain));
priv->set_server_ex_args_dirty = TRUE;
send_dnsmasq_update(self);
@ -1230,6 +1229,76 @@ update(NMDnsPlugin *plugin,
return TRUE;
}
static void
dnsmasq_checksum(const NML3ConfigData *l3cd,
GChecksum *sum,
int addr_family,
NMDnsIPConfigType dns_ip_config_type)
{
guint i;
NMDedupMultiIter ipconf_iter;
const NMPObject *obj;
const NMPlatformIPRoute *route;
const char *const *strarr;
const in_addr_t *wins;
guint element_num;
int prio = 0;
gboolean empty = TRUE;
g_return_if_fail(l3cd);
g_return_if_fail(sum);
strarr = nm_l3_config_data_get_nameservers(l3cd, addr_family, &element_num);
for (i = 0; i < element_num; i++) {
g_checksum_update(sum, (gpointer) strarr[i], strlen(strarr[i]));
empty = FALSE;
}
if (addr_family == AF_INET) {
wins = nm_l3_config_data_get_wins(l3cd, &element_num);
for (i = 0; i < element_num; i++) {
g_checksum_update(sum, (guint8 *) &wins[i], 4);
empty = FALSE;
}
}
/* Without servers, the sum should be zero, as Dnsmasq plugin depends on servers */
if (empty) {
return;
}
strarr = nm_l3_config_data_get_searches(l3cd, addr_family, &element_num);
for (i = 0; i < element_num; i++) {
g_checksum_update(sum, (const guint8 *) strarr[i], strlen(strarr[i]));
}
/* If we've got searches, then we do not care about domains, because
* searches have higher priority */
if (!element_num) {
strarr = nm_l3_config_data_get_domains(l3cd, addr_family, &element_num);
for (i = 0; i < element_num; i++) {
g_checksum_update(sum, (const guint8 *) strarr[i], strlen(strarr[i]));
}
}
/* Dnsmasq consumes reverse dns domains, thus it depends on routes */
nm_l3_config_data_iter_obj_for_each (&ipconf_iter,
l3cd,
&obj,
NMP_OBJECT_TYPE_IP_ROUTE(NM_IS_IPv4(addr_family))) {
route = NMP_OBJECT_CAST_IP_ROUTE(obj);
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT(route)
|| route->table_coerced == NM_DNS_ROUTES_FWMARK_TABLE_PRIO) {
continue;
}
g_checksum_update(sum, (const guint8 *) route, sizeof(*route));
}
g_checksum_update(sum, (const guint8 *) &dns_ip_config_type, sizeof(dns_ip_config_type));
nm_l3_config_data_get_dns_priority(l3cd, addr_family, &prio);
g_checksum_update(sum, (const guint8 *) &prio, sizeof(prio));
}
/*****************************************************************************/
static void
@ -1293,4 +1362,5 @@ nm_dns_dnsmasq_class_init(NMDnsDnsmasqClass *dns_class)
plugin_class->stop = stop;
plugin_class->update = update;
plugin_class->get_update_pending = get_update_pending;
plugin_class->checksum = dnsmasq_checksum;
}

File diff suppressed because it is too large Load diff

View file

@ -98,44 +98,6 @@ gboolean nm_dns_manager_set_ip_config(NMDnsManager *self,
void nm_dns_manager_set_hostname(NMDnsManager *self, const char *hostname, gboolean skip_update);
/**
* NMDnsManagerResolvConfManager
* @NM_DNS_MANAGER_RESOLV_CONF_MAN_UNKNOWN: unspecified rc-manager.
* @NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED: do not touch /etc/resolv.conf
* (but still write the internal copy -- unless it is symlinked by
* /etc/resolv.conf)
* @NM_DNS_MANAGER_RESOLV_CONF_MAN_AUTO: if /etc/resolv.conf is marked
* as an immutable file, use "unmanaged" and don't touch /etc/resolv.conf.
* Otherwise, if "systemd-resolved" is enabled (or detected), configure systemd-resolved via D-Bus
* and don't touch /etc/resolv.conf.
* Otherwise, if "resolvconf" application is found, use it.
* As last resort, fallback to "symlink" which writes to /etc/resolv.conf
* if (and only if) the file is missing or not a symlink.
* @NM_DNS_MANAGER_RESOLV_CONF_MAN_IMMUTABLE: similar to "unmanaged",
* but indicates that resolv.conf cannot be modified.
* @NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK: NM writes /etc/resolv.conf
* if the file is missing or not a symlink. An existing symlink is
* left untouched.
* @NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE: Write to /etc/resolv.conf directly.
* If it is a file, write it as file, otherwise follow symlinks.
* @NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF: NM is managing resolv.conf
through resolvconf
* @NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG: NM is managing resolv.conf
through netconfig
*
* NMDnsManager's management of resolv.conf
*/
typedef enum {
NM_DNS_MANAGER_RESOLV_CONF_MAN_UNKNOWN,
NM_DNS_MANAGER_RESOLV_CONF_MAN_AUTO,
NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED,
NM_DNS_MANAGER_RESOLV_CONF_MAN_IMMUTABLE,
NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK,
NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE,
NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF,
NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG,
} NMDnsManagerResolvConfManager;
void nm_dns_manager_stop(NMDnsManager *self);
NMDnsPlugin *nm_dns_manager_get_systemd_resolved(NMDnsManager *self);

View file

@ -62,22 +62,37 @@ G_DEFINE_ABSTRACT_TYPE(NMDnsPlugin, nm_dns_plugin, G_TYPE_OBJECT)
} \
G_STMT_END
NM_UTILS_LOOKUP_STR_DEFINE(
_rc_manager_to_string,
NMDnsManagerResolvConfManager,
NM_UTILS_LOOKUP_DEFAULT_WARN(NULL),
NM_UTILS_LOOKUP_STR_ITEM(NM_DNS_MANAGER_RESOLV_CONF_MAN_AUTO, "auto"),
NM_UTILS_LOOKUP_STR_ITEM(NM_DNS_MANAGER_RESOLV_CONF_MAN_UNKNOWN, "unknown"),
NM_UTILS_LOOKUP_STR_ITEM(NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED, "unmanaged"),
NM_UTILS_LOOKUP_STR_ITEM(NM_DNS_MANAGER_RESOLV_CONF_MAN_IMMUTABLE, "immutable"),
NM_UTILS_LOOKUP_STR_ITEM(NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK, "symlink"),
NM_UTILS_LOOKUP_STR_ITEM(NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE, "file"),
NM_UTILS_LOOKUP_STR_ITEM(NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF, "resolvconf"),
NM_UTILS_LOOKUP_STR_ITEM(NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG, "netconfig"), );
/*****************************************************************************/
gboolean
nm_dns_plugin_update(NMDnsPlugin *self,
const NMGlobalDnsConfig *global_config,
const CList *ip_config_lst_head,
const char *hostdomain,
GError **error)
nm_dns_plugin_update(NMDnsPlugin *self, NMDnsUpdateData *update_data, GError **error)
{
g_return_val_if_fail(NM_DNS_PLUGIN_GET_CLASS(self)->update != NULL, FALSE);
return NM_DNS_PLUGIN_GET_CLASS(self)->update(self,
global_config,
ip_config_lst_head,
hostdomain,
error);
return NM_DNS_PLUGIN_GET_CLASS(self)->update(self, update_data, error);
}
void
nm_dns_plugin_checksum(NMDnsPlugin *self,
const NML3ConfigData *l3cd,
GChecksum *sum,
int addr_family,
NMDnsIPConfigType dns_ip_config_type)
{
NM_DNS_PLUGIN_GET_CLASS(self)->checksum(l3cd, sum, addr_family, dns_ip_config_type);
}
gboolean
@ -98,6 +113,27 @@ nm_dns_plugin_get_name(NMDnsPlugin *self)
return klass->plugin_name;
}
const guint8 *
nm_dns_plugin_get_hash(NMDnsPlugin *self)
{
NMDnsPluginClass *klass;
g_return_val_if_fail(NM_IS_DNS_PLUGIN(self), NULL);
klass = NM_DNS_PLUGIN_GET_CLASS(self);
return klass->hash;
}
void
nm_dns_plugin_set_hash(NMDnsPlugin *self, guint8 *hash)
{
NMDnsPluginClass *klass;
klass = NM_DNS_PLUGIN_GET_CLASS(self);
memcpy(klass->hash, hash, NM_UTILS_CHECKSUM_LENGTH_SHA1);
}
void
nm_dns_plugin_stop(NMDnsPlugin *self)
{

View file

@ -21,6 +21,56 @@
#define NM_DNS_PLUGIN_UPDATE_PENDING_CHANGED "update-pending-changed"
/**
* NMDnsManagerResolvConfManager
* @NM_DNS_MANAGER_RESOLV_CONF_MAN_UNKNOWN: unspecified rc-manager.
* @NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED: do not touch /etc/resolv.conf
* (but still write the internal copy -- unless it is symlinked by
* /etc/resolv.conf)
* @NM_DNS_MANAGER_RESOLV_CONF_MAN_AUTO: if /etc/resolv.conf is marked
* as an immutable file, use "unmanaged" and don't touch /etc/resolv.conf.
* Otherwise, if "systemd-resolved" is enabled (or detected), configure systemd-resolved via D-Bus
* and don't touch /etc/resolv.conf.
* Otherwise, if "resolvconf" application is found, use it.
* As last resort, fallback to "symlink" which writes to /etc/resolv.conf
* if (and only if) the file is missing or not a symlink.
* @NM_DNS_MANAGER_RESOLV_CONF_MAN_IMMUTABLE: similar to "unmanaged",
* but indicates that resolv.conf cannot be modified.
* @NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK: NM writes /etc/resolv.conf
* if the file is missing or not a symlink. An existing symlink is
* left untouched.
* @NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE: Write to /etc/resolv.conf directly.
* If it is a file, write it as file, otherwise follow symlinks.
* @NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF: NM is managing resolv.conf
through resolvconf
* @NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG: NM is managing resolv.conf
through netconfig
*
* NMDnsManager's management of resolv.conf
*/
typedef enum {
NM_DNS_MANAGER_RESOLV_CONF_MAN_UNKNOWN,
NM_DNS_MANAGER_RESOLV_CONF_MAN_AUTO,
NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED,
NM_DNS_MANAGER_RESOLV_CONF_MAN_IMMUTABLE,
NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK,
NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE,
NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF,
NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG,
} NMDnsManagerResolvConfManager;
const char *_rc_manager_to_string(NMDnsManagerResolvConfManager val);
typedef struct {
const CList *ip_data_lst_head;
gboolean caching_successful;
gboolean resolved_used;
gboolean resolver_depends_on_nm;
NMDnsManagerResolvConfManager rc_manager;
const char *hostdomain;
NMGlobalDnsConfig *global_config;
} NMDnsUpdateData;
struct _NMDnsPluginPrivate;
typedef struct {
@ -36,11 +86,7 @@ typedef struct {
* 'global_config' is the optional global DNS
* configuration.
*/
gboolean (*update)(NMDnsPlugin *self,
const NMGlobalDnsConfig *global_config,
const CList *ip_config_lst_head,
const char *hostdomain,
GError **error);
gboolean (*update)(NMDnsPlugin *plugin, NMDnsUpdateData *update_data, GError **error);
void (*stop)(NMDnsPlugin *self);
@ -54,6 +100,15 @@ typedef struct {
*/
bool is_caching : 1;
guint8 hash[NM_UTILS_CHECKSUM_LENGTH_SHA1]; /* SHA1 hash of current plugin config */
/* Each way to set up resolution can be sensitive to different
* options or data, this function ensures that update is done
* only when relevant data change */
void (*checksum)(const NML3ConfigData *l3cd,
GChecksum *sum,
int addr_family,
NMDnsIPConfigType dns_ip_config_type);
} NMDnsPluginClass;
GType nm_dns_plugin_get_type(void);
@ -62,11 +117,17 @@ gboolean nm_dns_plugin_is_caching(NMDnsPlugin *self);
const char *nm_dns_plugin_get_name(NMDnsPlugin *self);
gboolean nm_dns_plugin_update(NMDnsPlugin *self,
const NMGlobalDnsConfig *global_config,
const CList *ip_config_lst_head,
const char *hostname,
GError **error);
const guint8 *nm_dns_plugin_get_hash(NMDnsPlugin *self);
void nm_dns_plugin_set_hash(NMDnsPlugin *self, guint8 *hash);
gboolean nm_dns_plugin_update(NMDnsPlugin *self, NMDnsUpdateData *update_data, GError **error);
void nm_dns_plugin_checksum(NMDnsPlugin *self,
const NML3ConfigData *l3cd,
GChecksum *sum,
int addr_family,
NMDnsIPConfigType dns_ip_config_type);
void nm_dns_plugin_stop(NMDnsPlugin *self);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,29 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2025 Red Hat, Inc.
*/
#ifndef __NETWORKMANAGER_DNS_RESOLVCONF_H__
#define __NETWORKMANAGER_DNS_RESOLVCONF_H__
#include "nm-dns-plugin.h"
#include "nm-dns-manager.h"
#define NM_TYPE_DNS_RESOLVCONF (nm_dns_resolvconf_get_type())
#define NM_DNS_RESOLVCONF(obj) \
(_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DNS_RESOLVCONF, NMDnsResolvconf))
#define NM_DNS_RESOLVCONF_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DNS_RESOLVCONF, NMDnsResolvconfClass))
#define NM_IS_DNS_RESOLVCONF(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DNS_RESOLVCONF))
#define NM_IS_DNS_RESOLVCONF_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DNS_RESOLVCONF))
#define NM_DNS_RESOLVCONF_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DNS_RESOLVCONF, NMDnsResolvconfClass))
typedef struct _NMDnsResolvconf NMDnsResolvconf;
typedef struct _NMDnsResolvconfClass NMDnsResolvconfClass;
GType nm_dns_resolvconf_get_type(void);
NMDnsPlugin *nm_dns_resolvconf_new(void);
#endif /* __NETWORKMANAGER_DNS_RESOLVCONF_H__ */

View file

@ -801,11 +801,7 @@ start_resolve:
}
static gboolean
update(NMDnsPlugin *plugin,
const NMGlobalDnsConfig *global_config,
const CList *ip_data_lst_head,
const char *hostdomain,
GError **error)
update(NMDnsPlugin *plugin, NMDnsUpdateData *update_data, GError **error)
{
NMDnsSystemdResolved *self = NM_DNS_SYSTEMD_RESOLVED(plugin);
NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
@ -826,7 +822,7 @@ update(NMDnsPlugin *plugin,
interfaces =
g_hash_table_new_full(nm_direct_hash, NULL, NULL, (GDestroyNotify) _interface_config_free);
c_list_for_each_entry (ip_data, ip_data_lst_head, ip_data_lst) {
c_list_for_each_entry (ip_data, update_data->ip_data_lst_head, ip_data_lst) {
InterfaceConfig *ic = NULL;
int ifindex = ip_data->data->ifindex;
@ -1241,6 +1237,68 @@ nm_dns_systemd_resolved_resolve_cancel(NMDnsSystemdResolvedResolveHandle *handle
_resolve_complete_error(handle, error);
}
static void
resolved_checksum(const NML3ConfigData *l3cd,
GChecksum *sum,
int addr_family,
NMDnsIPConfigType dns_ip_config_type)
{
guint i;
int val;
const char *const *strarr;
const in_addr_t *wins;
guint num_elements;
g_return_if_fail(l3cd);
g_return_if_fail(sum);
strarr = nm_l3_config_data_get_nameservers(l3cd, addr_family, &num_elements);
for (i = 0; i < num_elements; i++) {
g_checksum_update(sum, (gpointer) strarr[i], strlen(strarr[i]));
}
if (addr_family == AF_INET) {
wins = nm_l3_config_data_get_wins(l3cd, &num_elements);
for (i = 0; i < num_elements; i++) {
g_checksum_update(sum, (guint8 *) &wins[i], 4);
}
}
strarr = nm_l3_config_data_get_domains(l3cd, addr_family, &num_elements);
for (i = 0; i < num_elements; i++) {
g_checksum_update(sum, (const guint8 *) strarr[i], strlen(strarr[i]));
}
strarr = nm_l3_config_data_get_searches(l3cd, addr_family, &num_elements);
for (i = 0; i < num_elements; i++) {
g_checksum_update(sum, (const guint8 *) strarr[i], strlen(strarr[i]));
}
val = nm_l3_config_data_get_mdns(l3cd);
if (val != NM_SETTING_CONNECTION_MDNS_DEFAULT) {
g_checksum_update(sum, (const guint8 *) &val, sizeof(val));
}
val = nm_l3_config_data_get_llmnr(l3cd);
if (val != NM_SETTING_CONNECTION_LLMNR_DEFAULT) {
g_checksum_update(sum, (const guint8 *) &val, sizeof(val));
}
val = nm_l3_config_data_get_dns_over_tls(l3cd);
if (val != NM_SETTING_CONNECTION_DNS_OVER_TLS_DEFAULT) {
g_checksum_update(sum, (const guint8 *) &val, sizeof(val));
}
/* Priority has to be included everytime, because even if mdns/llmnr is
* left to default value, it could be enabled by default and priority
* would decide which interface should be used for mdns/llmnr */
val = 0;
g_checksum_update(sum, (const guint8 *) &dns_ip_config_type, sizeof(dns_ip_config_type));
nm_l3_config_data_get_dns_priority(l3cd, addr_family, &val);
g_checksum_update(sum, (const guint8 *) &val, sizeof(val));
}
/*****************************************************************************/
static void
@ -1354,4 +1412,5 @@ nm_dns_systemd_resolved_class_init(NMDnsSystemdResolvedClass *dns_class)
plugin_class->stop = stop;
plugin_class->update = update;
plugin_class->get_update_pending = get_update_pending;
plugin_class->checksum = resolved_checksum;
}

View file

@ -134,6 +134,7 @@ libNetworkManager = static_library(
'dhcp/nm-dhcp-listener.c',
'dns/nm-dns-dnsmasq.c',
'dns/nm-dns-dnsconfd.c',
'dns/nm-dns-resolv_conf.c',
'dns/nm-dns-manager.c',
'dns/nm-dns-plugin.c',
'dns/nm-dns-systemd-resolved.c',

View file

@ -1119,7 +1119,8 @@ nm_global_dns_config_update_checksum(const NMGlobalDnsConfig *dns_config, GCheck
v8 = NM_HASH_COMBINE_BOOLS(guint8,
!dns_config->searches,
!dns_config->options,
!dns_config->domain_list);
!dns_config->domain_list,
!dns_config->cert_authority);
g_checksum_update(sum, (guchar *) &v8, 1);
if (dns_config->searches) {
@ -1134,6 +1135,12 @@ nm_global_dns_config_update_checksum(const NMGlobalDnsConfig *dns_config, GCheck
(guchar *) dns_config->options[i],
strlen(dns_config->options[i]) + 1);
}
if (dns_config->cert_authority) {
g_checksum_update(sum,
(guchar *) dns_config->cert_authority,
strlen(dns_config->cert_authority) + 1);
}
g_checksum_update(sum, (guchar *) &dns_config->resolve_mode, sizeof(dns_config->resolve_mode));
if (dns_config->domain_list) {
for (i = 0; dns_config->domain_list[i]; i++) {

View file

@ -26,6 +26,10 @@
#include <netinet/ip6.h>
#include <linux/if_packet.h>
#if WITH_LIBPSL
#include <libpsl.h>
#endif
#include "libnm-glib-aux/nm-uuid.h"
#include "libnm-platform/nmp-base.h"
#include "libnm-std-aux/unaligned.h"
@ -4157,6 +4161,26 @@ nm_utils_g_value_set_strv(GValue *value, GPtrArray *strings)
g_value_take_boxed(value, strv);
}
void
nm_utils_g_ptr_array_add_string_item(GPtrArray *array, const char *str, gboolean dup)
{
int i;
g_return_if_fail(array != NULL);
g_return_if_fail(str != NULL);
/* Check for dupes before adding */
for (i = 0; i < array->len; i++) {
const char *candidate = g_ptr_array_index(array, i);
if (candidate && nm_streq(candidate, str))
return;
}
/* No dupes, add the new item */
g_ptr_array_add(array, dup ? g_strdup(str) : (gpointer) str);
}
/*****************************************************************************/
const char *
@ -4455,6 +4479,56 @@ nm_utils_parse_dns_domain(const char *domain, gboolean *is_routing)
return domain;
}
inline gboolean
nm_domain_is_routing(const char *domain)
{
return domain[0] == '~';
}
gboolean
nm_domain_is_valid(const char *domain,
gboolean reject_public_suffix,
gboolean assume_any_tld_is_public)
{
if (*domain == '\0')
return FALSE;
if (reject_public_suffix) {
int is_pub;
#if !WITH_LIBPSL
/* Without libpsl, we cannot detect that the domain is a public suffix, we assume
* the domain is not and valid. */
is_pub = FALSE;
#elif defined(PSL_TYPE_NO_STAR_RULE)
/*
* If we use PSL_TYPE_ANY, any TLD (top-level domain, i.e., domain
* with no dots) is considered *public* by the PSL library even if
* it is *not* on the official suffix list. This is the implicit
* behavior of the older API function psl_is_public_suffix().
* To inhibit that and only deem TLDs explicitly listed in the PSL
* as public, we need to turn off the "prevailing star rule" with
* PSL_TYPE_NO_STAR_RULE.
* For documentation on psl_is_public_suffix2(), see:
* https://rockdaboot.github.io/libpsl/libpsl-Public-Suffix-List-functions.html#psl-is-public-suffix2
* For more on the public suffix format, including wildcards:
* https://github.com/publicsuffix/list/wiki/Format#format
*/
is_pub =
psl_is_public_suffix2(psl_builtin(),
domain,
assume_any_tld_is_public ? PSL_TYPE_ANY : PSL_TYPE_NO_STAR_RULE);
#else
is_pub = psl_is_public_suffix(psl_builtin(), domain);
#endif
if (is_pub)
return FALSE;
}
return TRUE;
}
/*****************************************************************************/
static guint32

View file

@ -423,6 +423,8 @@ void _nm_utils_set_testing(NMUtilsTestFlags flags);
void nm_utils_g_value_set_strv(GValue *value, GPtrArray *strings);
void nm_utils_g_ptr_array_add_string_item(GPtrArray *array, const char *str, gboolean dup);
/*****************************************************************************/
const char *nm_utils_dnsmasq_status_to_string(int status, char *dest, gsize size);
@ -457,6 +459,12 @@ const char *nm_activation_type_to_string(NMActivationType activation_type);
const char *nm_utils_parse_dns_domain(const char *domain, gboolean *is_routing);
gboolean nm_domain_is_routing(const char *domain);
gboolean nm_domain_is_valid(const char *domain,
gboolean reject_public_suffix,
gboolean assume_any_tld_is_public);
/*****************************************************************************/
void nm_wifi_utils_parse_ies(const guint8 *bytes,

View file

@ -219,6 +219,43 @@ _garray_inaddr_clone(const GArray *src, int addr_family)
return dst;
}
void
nm_l3_config_data_get_dns_domains(GPtrArray *array,
int addr_family,
const NML3ConfigData *l3cd,
gboolean include_routing,
gboolean dup)
{
const char *const *domains;
const char *const *searches;
guint num_domains;
guint num_searches;
guint i;
const char *str;
domains = nm_l3_config_data_get_domains(l3cd, addr_family, &num_domains);
searches = nm_l3_config_data_get_searches(l3cd, addr_family, &num_searches);
for (i = 0; i < num_searches; i++) {
str = searches[i];
if (!include_routing && nm_domain_is_routing(str))
continue;
if (!nm_domain_is_valid(nm_utils_parse_dns_domain(str, NULL), FALSE, TRUE))
continue;
nm_utils_g_ptr_array_add_string_item(array, str, dup);
}
if (num_domains > 1 || num_searches == 0) {
for (i = 0; i < num_domains; i++) {
str = domains[i];
if (!include_routing && nm_domain_is_routing(str))
continue;
if (!nm_domain_is_valid(nm_utils_parse_dns_domain(str, NULL), FALSE, TRUE))
continue;
nm_utils_g_ptr_array_add_string_item(array, str, dup);
}
}
}
static void
_garray_inaddr_merge(GArray **p_dst, const GArray *src, int addr_family)
{

View file

@ -608,6 +608,12 @@ void nm_l3_config_data_set_allow_routes_without_address(NML3ConfigData *self,
gboolean nm_l3_config_data_get_routed_dns(const NML3ConfigData *self, int addr_family);
void nm_l3_config_data_set_routed_dns(NML3ConfigData *self, int addr_family, gboolean value);
void nm_l3_config_data_get_dns_domains(GPtrArray *array,
int addr_family,
const NML3ConfigData *l3cd,
gboolean include_routing,
gboolean dup);
NMProxyConfigMethod nm_l3_config_data_get_proxy_method(const NML3ConfigData *self);
gboolean nm_l3_config_data_set_proxy_method(NML3ConfigData *self, NMProxyConfigMethod value);