dns: merge branch 'bg/dns-bgo746422'

https://bugzilla.gnome.org/show_bug.cgi?id=746422
(cherry picked from commit d978258924)
This commit is contained in:
Beniamino Galvani 2018-10-18 17:25:00 +02:00
commit 6b8c6e891b
11 changed files with 322 additions and 269 deletions

View file

@ -216,7 +216,7 @@
#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_TIMEOUT N_("A timeout for a DHCP transaction in seconds.")
#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS N_("Array of IP addresses of DNS servers.")
#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_OPTIONS N_("Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties.")
#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_PRIORITY N_("Intra-connection DNS priority. The relative priority to be used when determining the order of DNS servers in resolv.conf. A lower value means that servers will be on top of the file. Zero selects the default value, which is 50 for VPNs and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections. It does not disambiguate multiple DNS servers within the same connection profile. For that, just specify the DNS servers in the desired order. When multiple devices have configurations with the same priority, the one with an active default route will be preferred. Note that when using dns=dnsmasq the order is meaningless since dnsmasq forwards queries to all known servers at the same time. Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least a negative priority, only DNS servers from connections with the lowest priority value will be used.")
#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_PRIORITY N_("DNS servers priority. The relative priority for DNS servers specified by this setting. A lower value is better (higher priority). Zero selects the default value, which is 50 for VPNs and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections. It does not disambiguate multiple DNS servers within the same connection profile. When using dns=default, servers with higher priority will be on top of resolv.conf. To prioritize a given server over another one within the same connection, just specify them in the desired order. When multiple devices have configurations with the same priority, the one with an active default route will be preferred. Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least a negative priority, only DNS servers from connections with the lowest priority value will be used. When using a DNS resolver that supports split-DNS as dns=dnsmasq or dns=systemd-resolved, each connection is used to query domains in its search list. Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually). When multiple connections specify the same domain, the one with the highest priority (lowest numerical value) wins. If a connection specifies a domain which is subdomain of another domain with a negative DNS priority value, the subdomain is ignored.")
#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_SEARCH N_("Array of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names.")
#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_GATEWAY N_("The gateway associated with this configuration. This is only meaningful if \"addresses\" is also set.")
#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_IGNORE_AUTO_DNS N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured nameservers and search domains are ignored and only nameservers and search domains specified in the \"dns\" and \"dns-search\" properties, if any, are used.")
@ -236,7 +236,7 @@
#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_TIMEOUT N_("A timeout for a DHCP transaction in seconds.")
#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS N_("Array of IP addresses of DNS servers.")
#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_OPTIONS N_("Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties.")
#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_PRIORITY N_("Intra-connection DNS priority. The relative priority to be used when determining the order of DNS servers in resolv.conf. A lower value means that servers will be on top of the file. Zero selects the default value, which is 50 for VPNs and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections. It does not disambiguate multiple DNS servers within the same connection profile. For that, just specify the DNS servers in the desired order. When multiple devices have configurations with the same priority, the one with an active default route will be preferred. Note that when using dns=dnsmasq the order is meaningless since dnsmasq forwards queries to all known servers at the same time. Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least a negative priority, only DNS servers from connections with the lowest priority value will be used.")
#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_PRIORITY N_("DNS servers priority. The relative priority for DNS servers specified by this setting. A lower value is better (higher priority). Zero selects the default value, which is 50 for VPNs and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections. It does not disambiguate multiple DNS servers within the same connection profile. When using dns=default, servers with higher priority will be on top of resolv.conf. To prioritize a given server over another one within the same connection, just specify them in the desired order. When multiple devices have configurations with the same priority, the one with an active default route will be preferred. Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least a negative priority, only DNS servers from connections with the lowest priority value will be used. When using a DNS resolver that supports split-DNS as dns=dnsmasq or dns=systemd-resolved, each connection is used to query domains in its search list. Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually). When multiple connections specify the same domain, the one with the highest priority (lowest numerical value) wins. If a connection specifies a domain which is subdomain of another domain with a negative DNS priority value, the subdomain is ignored.")
#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_SEARCH N_("Array of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names.")
#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_GATEWAY N_("The gateway associated with this configuration. This is only meaningful if \"addresses\" is also set.")
#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_IGNORE_AUTO_DNS N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured nameservers and search domains are ignored and only nameservers and search domains specified in the \"dns\" and \"dns-search\" properties, if any, are used.")

View file

@ -2993,24 +2993,34 @@ nm_setting_ip_config_class_init (NMSettingIPConfigClass *setting_class)
/**
* NMSettingIPConfig:dns-priority:
*
* Intra-connection DNS priority.
* DNS servers priority.
*
* The relative priority to be used when determining the order of DNS
* servers in resolv.conf. A lower value means that servers will be on top
* of the file. Zero selects the default value, which is 50 for VPNs and
* 100 for other connections. Note that the priority is to order DNS
* settings for multiple active connections. It does not disambiguate
* multiple DNS servers within the same connection profile. For that,
* just specify the DNS servers in the desired order.
* When multiple devices have configurations with the same priority, the
* one with an active default route will be preferred.
* Note that when using dns=dnsmasq the order is meaningless
* since dnsmasq forwards queries to all known servers at the same time.
* The relative priority for DNS servers specified by this setting. A lower
* value is better (higher priority). Zero selects the default value, which
* is 50 for VPNs and 100 for other connections.
*
* Negative values have the special effect of excluding other configurations
* with a greater priority value; so in presence of at least a negative
* priority, only DNS servers from connections with the lowest priority
* value will be used.
* Note that the priority is to order DNS settings for multiple active
* connections. It does not disambiguate multiple DNS servers within the
* same connection profile.
*
* When using dns=default, servers with higher priority will be on top of
* resolv.conf. To prioritize a given server over another one within the
* same connection, just specify them in the desired order. When multiple
* devices have configurations with the same priority, the one with an
* active default route will be preferred. Negative values have the special
* effect of excluding other configurations with a greater priority value;
* so in presence of at least a negative priority, only DNS servers from
* connections with the lowest priority value will be used.
*
* When using a DNS resolver that supports split-DNS as dns=dnsmasq or
* dns=systemd-resolved, each connection is used to query domains in its
* search list. Queries for domains not present in any search list are
* routed through connections having the '~.' special wildcard domain, which
* is added automatically to connections with the default route (or can be
* added manually). When multiple connections specify the same domain, the
* one with the highest priority (lowest numerical value) wins. If a
* connection specifies a domain which is subdomain of another domain with a
* negative DNS priority value, the subdomain is ignored.
*
* Since: 1.4
**/

View file

@ -75,53 +75,6 @@ G_DEFINE_TYPE (NMDnsDnsmasq, nm_dns_dnsmasq, NM_TYPE_DNS_PLUGIN)
/*****************************************************************************/
static char **
get_ip_rdns_domains (NMIPConfig *ip_config)
{
int addr_family = nm_ip_config_get_addr_family (ip_config);
char **strv;
GPtrArray *domains = NULL;
NMDedupMultiIter ipconf_iter;
nm_assert_addr_family (addr_family);
domains = g_ptr_array_sized_new (5);
if (addr_family == AF_INET) {
NMIP4Config *ip4 = (gpointer) ip_config;
const NMPlatformIP4Address *address;
const NMPlatformIP4Route *route;
nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, ip4, &address)
nm_utils_get_reverse_dns_domains_ip4 (address->address, address->plen, domains);
nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, ip4, &route) {
if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route))
nm_utils_get_reverse_dns_domains_ip4 (route->network, route->plen, domains);
}
} else {
NMIP6Config *ip6 = (gpointer) ip_config;
const NMPlatformIP6Address *address;
const NMPlatformIP6Route *route;
nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, ip6, &address)
nm_utils_get_reverse_dns_domains_ip6 (&address->address, address->plen, domains);
nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &route) {
if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route))
nm_utils_get_reverse_dns_domains_ip6 (&route->network, route->plen, domains);
}
}
/* Terminating NULL so we can use g_strfreev() to free it */
g_ptr_array_add (domains, NULL);
/* Free the array and return NULL if the only element was the ending NULL */
strv = (char **) g_ptr_array_free (domains, (domains->len == 1));
return _nm_utils_strv_cleanup (strv, FALSE, FALSE, TRUE);
}
static void
add_dnsmasq_nameserver (NMDnsDnsmasq *self,
GVariantBuilder *servers,
@ -206,91 +159,34 @@ add_global_config (NMDnsDnsmasq *self, GVariantBuilder *dnsmasq_servers, const N
}
static void
add_ip_config (NMDnsDnsmasq *self,
GVariantBuilder *servers,
int ifindex,
NMIPConfig *ip_config,
gboolean split)
add_ip_config (NMDnsDnsmasq *self, GVariantBuilder *servers, const NMDnsIPConfigData *ip_data)
{
int addr_family;
NMIPConfig *ip_config = ip_data->ip_config;
gconstpointer addr;
gboolean added = FALSE;
guint nnameservers, i_nameserver, n, i;
const char *iface, *domain;
char ip_addr_to_string_buf[IP_ADDR_TO_STRING_BUFLEN];
char **domains, **iter;
gboolean iface_resolved = FALSE;
const char *iface = NULL, *domain;
int addr_family;
guint i, j, num;
iface = nm_platform_link_get_name (NM_PLATFORM_GET, ip_data->data->ifindex);
addr_family = nm_ip_config_get_addr_family (ip_config);
g_return_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6));
nm_assert (ifindex > 0);
nm_assert (ifindex == nm_ip_config_get_ifindex (ip_config));
nnameservers = nm_ip_config_get_num_nameservers (ip_config);
if (split) {
if (nnameservers == 0)
return;
if (!iface_resolved) {
iface = nm_platform_link_get_name (NM_PLATFORM_GET, ifindex);
iface_resolved = TRUE;
num = nm_ip_config_get_num_nameservers (ip_config);
for (i = 0; i < num; i++) {
addr = nm_ip_config_get_nameserver (ip_config, i);
ip_addr_to_string (addr_family, addr, iface, ip_addr_to_string_buf);
for (j = 0; ip_data->domains.search[j]; j++) {
domain = nm_utils_parse_dns_domain (ip_data->domains.search[j], NULL);
add_dnsmasq_nameserver (self,
servers,
ip_addr_to_string_buf,
domain[0] ? domain : NULL);
}
if (iface) {
for (i_nameserver = 0; i_nameserver < nnameservers; i_nameserver++) {
addr = nm_ip_config_get_nameserver (ip_config, i_nameserver);
ip_addr_to_string (addr_family, addr, iface, ip_addr_to_string_buf);
/* searches are preferred over domains */
n = nm_ip_config_get_num_searches (ip_config);
for (i = 0; i < n; i++) {
domain = nm_utils_parse_dns_domain (nm_ip_config_get_search (ip_config, i), NULL);
add_dnsmasq_nameserver (self,
servers,
ip_addr_to_string_buf,
domain);
added = TRUE;
}
if (n == 0) {
/* If not searches, use any domains */
n = nm_ip_config_get_num_domains (ip_config);
domain = nm_utils_parse_dns_domain (nm_ip_config_get_domain (ip_config, i), NULL);
for (i = 0; i < n; i++) {
add_dnsmasq_nameserver (self,
servers,
ip_addr_to_string_buf,
domain);
added = TRUE;
}
}
/* Ensure reverse-DNS works by directing queries for in-addr4.arpa/ip6.arpa
* domains to the split domain's nameserver.
*/
domains = get_ip_rdns_domains (ip_config);
if (domains) {
for (iter = domains; *iter; iter++)
add_dnsmasq_nameserver (self, servers, ip_addr_to_string_buf, *iter);
g_strfreev (domains);
}
}
}
}
/* If no searches or domains, just add the nameservers */
if (!added) {
if (!iface_resolved)
iface = nm_platform_link_get_name (NM_PLATFORM_GET, ifindex);
if (iface) {
for (i = 0; i < nnameservers; i++) {
addr = nm_ip_config_get_nameserver (ip_config, i);
ip_addr_to_string (addr_family, addr, iface, ip_addr_to_string_buf);
add_dnsmasq_nameserver (self, servers, ip_addr_to_string_buf, NULL);
}
for (j = 0; ip_data->domains.reverse[j]; j++) {
add_dnsmasq_nameserver (self, servers,
ip_addr_to_string_buf,
ip_data->domains.reverse[j]);
}
}
}
@ -489,9 +385,7 @@ update (NMDnsPlugin *plugin,
NMDnsDnsmasq *self = NM_DNS_DNSMASQ (plugin);
NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self);
GVariantBuilder servers;
int prio, first_prio;
const NMDnsIPConfigData *ip_data;
gboolean is_first = TRUE;
start_dnsmasq (self);
@ -500,19 +394,8 @@ update (NMDnsPlugin *plugin,
if (global_config)
add_global_config (self, &servers, global_config);
else {
c_list_for_each_entry (ip_data, ip_config_lst_head, ip_config_lst) {
prio = nm_ip_config_get_dns_priority (ip_data->ip_config);
if (is_first) {
is_first = FALSE;
first_prio = prio;
} else if (first_prio < 0 && first_prio != prio)
break;
add_ip_config (self,
&servers,
ip_data->data->ifindex,
ip_data->ip_config,
ip_data->ip_config_type == NM_DNS_IP_CONFIG_TYPE_VPN);
}
c_list_for_each_entry (ip_data, ip_config_lst_head, ip_config_lst)
add_ip_config (self, &servers, ip_data);
}
g_clear_pointer (&priv->set_server_ex_args, g_variant_unref);

View file

@ -274,6 +274,9 @@ _ip_config_data_free (NMDnsIPConfigData *ip_data)
c_list_unlink_stale (&ip_data->data_lst);
c_list_unlink_stale (&ip_data->ip_config_lst);
g_free (ip_data->domains.search);
g_strfreev (ip_data->domains.reverse);
g_signal_handlers_disconnect_by_func (ip_data->ip_config,
_ip_config_dns_priority_changed,
ip_data);
@ -1130,6 +1133,197 @@ _collect_resolv_conf_data (NMDnsManager *self,
*out_nis_domain = rc.nis_domain;
}
static char **
get_ip_rdns_domains (NMIPConfig *ip_config)
{
int addr_family = nm_ip_config_get_addr_family (ip_config);
char **strv;
GPtrArray *domains = NULL;
NMDedupMultiIter ipconf_iter;
nm_assert_addr_family (addr_family);
domains = g_ptr_array_sized_new (5);
if (addr_family == AF_INET) {
NMIP4Config *ip4 = (gpointer) ip_config;
const NMPlatformIP4Address *address;
const NMPlatformIP4Route *route;
nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, ip4, &address)
nm_utils_get_reverse_dns_domains_ip4 (address->address, address->plen, domains);
nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, ip4, &route) {
if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route))
nm_utils_get_reverse_dns_domains_ip4 (route->network, route->plen, domains);
}
} else {
NMIP6Config *ip6 = (gpointer) ip_config;
const NMPlatformIP6Address *address;
const NMPlatformIP6Route *route;
nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, ip6, &address)
nm_utils_get_reverse_dns_domains_ip6 (&address->address, address->plen, domains);
nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &route) {
if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route))
nm_utils_get_reverse_dns_domains_ip6 (&route->network, route->plen, domains);
}
}
/* Terminating NULL so we can use g_strfreev() to free it */
g_ptr_array_add (domains, NULL);
/* Free the array and return NULL if the only element was the ending NULL */
strv = (char **) g_ptr_array_free (domains, (domains->len == 1));
return _nm_utils_strv_cleanup (strv, FALSE, FALSE, TRUE);
}
/* Check if the domain is shadowed by a parent domain with more negative priority */
static gboolean
domain_is_shadowed (GHashTable *ht,
const char *domain, int priority,
const char **out_parent, int *out_parent_priority)
{
char *parent;
int parent_priority;
nm_assert (!g_hash_table_contains (ht, domain));
parent_priority = GPOINTER_TO_INT (g_hash_table_lookup (ht, ""));
if (parent_priority < 0 && parent_priority < priority) {
*out_parent = "";
*out_parent_priority = parent_priority;
return TRUE;
}
parent = strchr (domain, '.');
while (parent && parent[1]) {
parent++;
parent_priority = GPOINTER_TO_INT (g_hash_table_lookup (ht, parent));
if (parent_priority < 0 && parent_priority < priority) {
*out_parent = parent;
*out_parent_priority = parent_priority;
return TRUE;
}
parent = strchr (parent, '.');
}
return FALSE;
}
static void
rebuild_domain_lists (NMDnsManager *self)
{
NMDnsIPConfigData *ip_data;
gs_unref_hashtable GHashTable *ht = NULL;
gboolean default_route_found = FALSE;
CList *head;
ht = g_hash_table_new (nm_str_hash, g_str_equal);
head = _ip_config_lst_head (self);
c_list_for_each_entry (ip_data, head, ip_config_lst) {
NMIPConfig *ip_config = ip_data->ip_config;
if (!nm_ip_config_get_num_nameservers (ip_config))
continue;
if (nm_ip_config_best_default_route_get (ip_config)) {
default_route_found = TRUE;
break;
}
}
c_list_for_each_entry (ip_data, head, ip_config_lst) {
NMIPConfig *ip_config = ip_data->ip_config;
int priority, old_priority;
guint i, n, n_domains = 0;
const char **domains;
if (!nm_ip_config_get_num_nameservers (ip_config))
continue;
priority = nm_ip_config_get_dns_priority (ip_config);
nm_assert (priority != 0);
g_free (ip_data->domains.search);
domains = g_new0 (const char *,
2 + NM_MAX (nm_ip_config_get_num_searches (ip_config),
nm_ip_config_get_num_domains (ip_config)));
ip_data->domains.search = domains;
/* Add wildcard lookup domain to connections with the default route.
* If there is no default route, add the wildcard domain to all non-VPN
* connections */
if (default_route_found) {
if (nm_ip_config_best_default_route_get (ip_config))
domains[n_domains++] = "~";
} else {
if (ip_data->ip_config_type != NM_DNS_IP_CONFIG_TYPE_VPN)
domains[n_domains++] = "~";
}
/* searches are preferred over domains */
n = nm_ip_config_get_num_searches (ip_config);
for (i = 0; i < n; i++)
domains[n_domains++] = nm_ip_config_get_search (ip_config, i);
if (n == 0) {
/* If not searches, use any domains */
n = nm_ip_config_get_num_domains (ip_config);
for (i = 0; i < n; i++)
domains[n_domains++] = nm_ip_config_get_domain (ip_config, i);
}
n = 0;
for (i = 0; i < n_domains; i++) {
const char *domain_clean;
const char *parent;
int parent_priority;
domain_clean = nm_utils_parse_dns_domain (domains[i], NULL);
/* Remove domains with lower priority */
old_priority = GPOINTER_TO_INT (g_hash_table_lookup (ht, domain_clean));
if (old_priority) {
if (old_priority < priority) {
_LOGT ("plugin: drop domain '%s' (i=%d, p=%d) because it already exists with p=%d",
domains[i], ip_data->data->ifindex,
priority, old_priority);
continue;
}
} else if (domain_is_shadowed (ht, domain_clean, priority, &parent, &parent_priority)) {
_LOGT ("plugin: drop domain '%s' (i=%d, p=%d) shadowed by '%s' (p=%d)",
domains[i],
ip_data->data->ifindex, priority,
parent, parent_priority);
continue;
}
_LOGT ("plugin: add domain '%s' (i=%d, p=%d)", domains[i], ip_data->data->ifindex, priority);
g_hash_table_insert (ht, (gpointer) domain_clean, GINT_TO_POINTER (priority));
domains[n++] = domains[i];
}
domains[n] = NULL;
g_strfreev (ip_data->domains.reverse);
ip_data->domains.reverse = get_ip_rdns_domains (ip_config);
}
}
static void
clear_domain_lists (NMDnsManager *self)
{
NMDnsIPConfigData *ip_data;
CList *head;
head = _ip_config_lst_head (self);
c_list_for_each_entry (ip_data, head, ip_config_lst) {
g_clear_pointer (&ip_data->domains.search, g_free);
g_clear_pointer (&ip_data->domains.reverse, g_strfreev);
}
}
static gboolean
update_dns (NMDnsManager *self,
gboolean no_caching,
@ -1192,6 +1386,7 @@ update_dns (NMDnsManager *self,
}
_LOGD ("update-dns: updating plugin %s", plugin_name);
rebuild_domain_lists (self);
if (!nm_dns_plugin_update (plugin,
global_config,
_ip_config_lst_head (self),
@ -1203,6 +1398,10 @@ update_dns (NMDnsManager *self,
*/
caching = FALSE;
}
/* Clear the generated search list as it points to
* strings owned by IP configurations and we can't
* guarantee they stay alive. */
clear_domain_lists (self);
skip:
;

View file

@ -50,6 +50,10 @@ typedef struct {
CList data_lst;
CList ip_config_lst;
NMDnsIPConfigType ip_config_type;
struct {
const char **search;
char **reverse;
} domains;
} NMDnsIPConfigData;
typedef struct _NMDnsConfigData {

View file

@ -141,47 +141,36 @@ static void
update_add_ip_config (NMDnsSystemdResolved *self,
GVariantBuilder *dns,
GVariantBuilder *domains,
NMIPConfig *config)
NMDnsIPConfigData *data)
{
int addr_family;
gsize addr_size;
guint i, n;
gboolean is_routing;
const char **iter;
const char *domain;
addr_family = nm_ip_config_get_addr_family (config);
addr_family = nm_ip_config_get_addr_family (data->ip_config);
addr_size = nm_utils_addr_family_to_size (addr_family);
n = nm_ip_config_get_num_nameservers (config);
if (!data->domains.search || !data->domains.search[0])
return;
n = nm_ip_config_get_num_nameservers (data->ip_config);
for (i = 0 ; i < n; i++) {
g_variant_builder_open (dns, G_VARIANT_TYPE ("(iay)"));
g_variant_builder_add (dns, "i", addr_family);
g_variant_builder_add_value (dns,
g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
nm_ip_config_get_nameserver (config, i),
nm_ip_config_get_nameserver (data->ip_config, i),
addr_size,
1));
g_variant_builder_close (dns);
}
n = nm_ip_config_get_num_searches (config);
if (n > 0) {
for (i = 0; i < n; i++) {
domain = nm_utils_parse_dns_domain (nm_ip_config_get_search (config, i),
&is_routing);
g_variant_builder_add (domains, "(sb)",
domain,
is_routing);
}
} else {
n = nm_ip_config_get_num_domains (config);
for (i = 0; i < n; i++) {
domain = nm_utils_parse_dns_domain (nm_ip_config_get_domain (config, i),
&is_routing);
g_variant_builder_add (domains, "(sb)",
domain,
is_routing);
}
for (iter = data->domains.search; *iter; iter++) {
domain = nm_utils_parse_dns_domain (*iter, &is_routing);
g_variant_builder_add (domains, "(sb)", domain[0] ? domain : ".", is_routing);
}
}
@ -216,9 +205,10 @@ prepare_one_interface (NMDnsSystemdResolved *self, InterfaceConfig *ic)
g_variant_builder_open (&domains, G_VARIANT_TYPE ("a(sb)"));
c_list_for_each_entry (elem, &ic->configs_lst_head, lst) {
NMIPConfig *ip_config = elem->data;
NMDnsIPConfigData *data = elem->data;
NMIPConfig *ip_config = data->ip_config;
update_add_ip_config (self, &dns, &domains, ip_config);
update_add_ip_config (self, &dns, &domains, data);
if (NM_IS_IP4_CONFIG (ip_config))
mdns = NM_MAX (mdns, nm_ip4_config_mdns_get (NM_IP4_CONFIG (ip_config)));
@ -294,25 +284,15 @@ update (NMDnsPlugin *plugin,
gs_free gpointer *interfaces_keys = NULL;
guint interfaces_len;
guint i;
int prio, first_prio = 0;
NMDnsIPConfigData *ip_data;
gboolean is_first = TRUE;
interfaces = g_hash_table_new_full (nm_direct_hash, NULL,
NULL, (GDestroyNotify) _interface_config_free);
c_list_for_each_entry (ip_data, ip_config_lst_head, ip_config_lst) {
gboolean skip = FALSE;
InterfaceConfig *ic = NULL;
int ifindex;
prio = nm_ip_config_get_dns_priority (ip_data->ip_config);
if (is_first) {
is_first = FALSE;
first_prio = prio;
} else if (first_prio < 0 && first_prio != prio)
skip = TRUE;
ifindex = ip_data->data->ifindex;
nm_assert (ifindex == nm_ip_config_get_ifindex (ip_data->ip_config));
@ -324,10 +304,8 @@ update (NMDnsPlugin *plugin,
g_hash_table_insert (interfaces, GINT_TO_POINTER (ifindex), ic);
}
if (!skip) {
c_list_link_tail (&ic->configs_lst_head,
&nm_c_list_elem_new_stale (ip_data->ip_config)->lst);
}
c_list_link_tail (&ic->configs_lst_head,
&nm_c_list_elem_new_stale (ip_data)->lst);
}
free_pending_updates (self);

View file

@ -2286,6 +2286,31 @@ _nm_ip4_config_get_nameserver (const NMIP4Config *self, guint i)
/*****************************************************************************/
gboolean
_nm_ip_config_check_and_add_domain (GPtrArray *array, const char *domain)
{
char *copy = NULL;
size_t len;
g_return_val_if_fail (domain, FALSE);
g_return_val_if_fail (domain[0] != '\0', FALSE);
if (domain[0] == '.' || strstr (domain, ".."))
return FALSE;
len = strlen (domain);
if (domain[len - 1] == '.')
domain = copy = g_strndup (domain, len - 1);
if (nm_utils_strv_find_first ((char **) array->pdata, array->len, domain) >= 0) {
g_free (copy);
return FALSE;
}
g_ptr_array_add (array, copy ?: g_strdup (domain));
return TRUE;
}
void
nm_ip4_config_reset_domains (NMIP4Config *self)
{
@ -2301,17 +2326,9 @@ void
nm_ip4_config_add_domain (NMIP4Config *self, const char *domain)
{
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
int i;
g_return_if_fail (domain != NULL);
g_return_if_fail (domain[0] != '\0');
for (i = 0; i < priv->domains->len; i++)
if (!g_strcmp0 (g_ptr_array_index (priv->domains, i), domain))
return;
g_ptr_array_add (priv->domains, g_strdup (domain));
_notify (self, PROP_DOMAINS);
if (_nm_ip_config_check_and_add_domain (priv->domains, domain))
_notify (self, PROP_DOMAINS);
}
void
@ -2355,35 +2372,12 @@ nm_ip4_config_reset_searches (NMIP4Config *self)
}
void
nm_ip4_config_add_search (NMIP4Config *self, const char *new)
nm_ip4_config_add_search (NMIP4Config *self, const char *search)
{
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
char *search;
size_t len;
g_return_if_fail (new != NULL);
g_return_if_fail (new[0] != '\0');
search = g_strdup (new);
/* Remove trailing dot as it has no effect */
len = strlen (search);
if (search[len - 1] == '.')
search[len - 1] = 0;
if (!search[0]) {
g_free (search);
return;
}
if (nm_utils_strv_find_first ((char **) priv->searches->pdata,
priv->searches->len, search) >= 0) {
g_free (search);
return;
}
g_ptr_array_add (priv->searches, search);
_notify (self, PROP_SEARCHES);
if (_nm_ip_config_check_and_add_domain (priv->searches, search))
_notify (self, PROP_SEARCHES);
}
void

View file

@ -280,6 +280,8 @@ gboolean nm_ip4_config_nmpobj_remove (NMIP4Config *self,
void nm_ip4_config_hash (const NMIP4Config *self, GChecksum *sum, gboolean dns_only);
gboolean nm_ip4_config_equal (const NMIP4Config *a, const NMIP4Config *b);
gboolean _nm_ip_config_check_and_add_domain (GPtrArray *array, const char *domain);
/*****************************************************************************/
#include "nm-ip6-config.h"
@ -435,4 +437,10 @@ nm_ip_config_get_dns_option (const NMIPConfig *self, guint i)
_NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_dns_option, nm_ip6_config_get_dns_option, i);
}
static inline const NMPObject *
nm_ip_config_best_default_route_get (const NMIPConfig *self)
{
_NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_best_default_route_get, nm_ip6_config_best_default_route_get);
}
#endif /* __NETWORKMANAGER_IP4_CONFIG_H__ */

View file

@ -2054,17 +2054,9 @@ void
nm_ip6_config_add_domain (NMIP6Config *self, const char *domain)
{
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
int i;
g_return_if_fail (domain != NULL);
g_return_if_fail (domain[0] != '\0');
for (i = 0; i < priv->domains->len; i++)
if (!g_strcmp0 (g_ptr_array_index (priv->domains, i), domain))
return;
g_ptr_array_add (priv->domains, g_strdup (domain));
_notify (self, PROP_DOMAINS);
if (_nm_ip_config_check_and_add_domain (priv->domains, domain))
_notify (self, PROP_DOMAINS);
}
void
@ -2108,35 +2100,12 @@ nm_ip6_config_reset_searches (NMIP6Config *self)
}
void
nm_ip6_config_add_search (NMIP6Config *self, const char *new)
nm_ip6_config_add_search (NMIP6Config *self, const char *search)
{
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
char *search;
size_t len;
g_return_if_fail (new != NULL);
g_return_if_fail (new[0] != '\0');
search = g_strdup (new);
/* Remove trailing dot as it has no effect */
len = strlen (search);
if (search[len - 1] == '.')
search[len - 1] = 0;
if (!search[0]) {
g_free (search);
return;
}
if (nm_utils_strv_find_first ((char **) priv->searches->pdata,
priv->searches->len, search) >= 0) {
g_free (search);
return;
}
g_ptr_array_add (priv->searches, search);
_notify (self, PROP_SEARCHES);
if (_nm_ip_config_check_and_add_domain (priv->searches, search))
_notify (self, PROP_SEARCHES);
}
void

View file

@ -319,11 +319,15 @@ test_strip_search_trailing_dot (void)
nm_ip4_config_add_search (config, "bar.");
nm_ip4_config_add_search (config, "baz.com");
nm_ip4_config_add_search (config, "baz.com.");
nm_ip4_config_add_search (config, "foobar..");
nm_ip4_config_add_search (config, ".foobar");
nm_ip4_config_add_search (config, "~.");
g_assert_cmpuint (nm_ip4_config_get_num_searches (config), ==, 3);
g_assert_cmpuint (nm_ip4_config_get_num_searches (config), ==, 4);
g_assert_cmpstr (nm_ip4_config_get_search (config, 0), ==, "foo");
g_assert_cmpstr (nm_ip4_config_get_search (config, 1), ==, "bar");
g_assert_cmpstr (nm_ip4_config_get_search (config, 2), ==, "baz.com");
g_assert_cmpstr (nm_ip4_config_get_search (config, 3), ==, "~");
g_object_unref (config);
}

View file

@ -338,11 +338,15 @@ test_strip_search_trailing_dot (void)
nm_ip6_config_add_search (config, "bar.");
nm_ip6_config_add_search (config, "baz.com");
nm_ip6_config_add_search (config, "baz.com.");
nm_ip6_config_add_search (config, "foobar..");
nm_ip6_config_add_search (config, ".foobar");
nm_ip6_config_add_search (config, "~.");
g_assert_cmpuint (nm_ip6_config_get_num_searches (config), ==, 3);
g_assert_cmpuint (nm_ip6_config_get_num_searches (config), ==, 4);
g_assert_cmpstr (nm_ip6_config_get_search (config, 0), ==, "foo");
g_assert_cmpstr (nm_ip6_config_get_search (config, 1), ==, "bar");
g_assert_cmpstr (nm_ip6_config_get_search (config, 2), ==, "baz.com");
g_assert_cmpstr (nm_ip6_config_get_search (config, 3), ==, "~");
g_object_unref (config);
}