diff options
author | Tom Sobczynski <tsobczynski@gmail.com> | 2023-04-25 19:19:30 -0400 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2023-05-02 11:23:09 +0200 |
commit | 86bb09c93be39d5a8c6602cdfb7958bde5c29059 (patch) | |
tree | f6daa11d6303ddc514bbe530529f1db61a22a8c1 | |
parent | cb6f8b987c2b34d1ad325a0faf5a3a9d1d661ce2 (diff) | |
download | NetworkManager-86bb09c93be39d5a8c6602cdfb7958bde5c29059.tar.gz |
dns: generate correct search domain for hostnames on non-public TLD
dns-manager uses the Mozilla Public Suffix List to determine an
appropriate search domain when generating /etc/resolv.conf. It is
presumed that if the hostname is "example.com", the user does not want
to automatically search "com" for unqualified hostnames, which is
reasonable. To implement that, prior to the fix, domain_is_valid()
implicitly used the PSL "prevailing star rule", which had the
consequence of assuming that any top-level domain (TLD) is public
whether it is on the official suffix list or not. That meant
"example.local" or "example.localdomain" would not result in searching
"local" or "localdomain" respectively, but rather /etc/resolv.conf would
contain the full hostname "example.local" as the search domain and not
give users what they expect. The fix here uses the newer PSL API
function that allows us to turn off the "prevailing star rule" so that
"local" and "localdomain" are NOT considered public TLDs because they
are not literally on the suffix list. That in turn gives us the search
domain "local" or "localdomain" in /etc/resolv.conf and allows
unqualified hostname lookups "e.g., resolvectl query example" to find
example.local while example.com still maintains the previous behavior
(i.e., search domain of "example.com" rather than "com").
[thaller@redhat.com: reworded commit message]
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/1281
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1613
-rw-r--r-- | src/core/dns/nm-dns-manager.c | 51 |
1 files changed, 43 insertions, 8 deletions
diff --git a/src/core/dns/nm-dns-manager.c b/src/core/dns/nm-dns-manager.c index fb65afcadc..e4181de30a 100644 --- a/src/core/dns/nm-dns-manager.c +++ b/src/core/dns/nm-dns-manager.c @@ -173,14 +173,42 @@ NM_DEFINE_SINGLETON_GETTER(NMDnsManager, nm_dns_manager_get, NM_TYPE_DNS_MANAGER /*****************************************************************************/ static gboolean -domain_is_valid(const char *domain, gboolean check_public_suffix) +domain_is_valid(const char *domain, gboolean check_public_suffix, gboolean assume_any_tld_is_public) { +#if WITH_LIBPSL + /* ifdef to fall back to old API function on platforms with older LIBPSL */ +#ifdef PSL_TYPE_NO_STAR_RULE + int type = PSL_TYPE_ANY; +#endif +#endif + if (*domain == '\0') return FALSE; #if WITH_LIBPSL + /* ifdef to fall back to old API function on platforms with older LIBPSL */ +#ifdef 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 + */ + if (!assume_any_tld_is_public) + type = PSL_TYPE_NO_STAR_RULE; + if (check_public_suffix && psl_is_public_suffix2(psl_builtin(), domain, type)) + return FALSE; +#else if (check_public_suffix && psl_is_public_suffix(psl_builtin(), domain)) return FALSE; #endif +#endif return TRUE; } @@ -533,7 +561,7 @@ add_dns_domains(GPtrArray *array, str = searches[i]; if (!include_routing && domain_is_routing(str)) continue; - if (!domain_is_valid(nm_utils_parse_dns_domain(str, NULL), FALSE)) + if (!domain_is_valid(nm_utils_parse_dns_domain(str, NULL), FALSE, TRUE)) continue; add_string_item(array, str, dup); } @@ -542,7 +570,7 @@ add_dns_domains(GPtrArray *array, str = domains[i]; if (!include_routing && domain_is_routing(str)) continue; - if (!domain_is_valid(nm_utils_parse_dns_domain(str, NULL), FALSE)) + if (!domain_is_valid(nm_utils_parse_dns_domain(str, NULL), FALSE, TRUE)) continue; add_string_item(array, str, dup); } @@ -1236,7 +1264,7 @@ merge_global_dns_config(NMResolvConfData *rc, NMGlobalDnsConfig *global_conf) for (i = 0; searches[i]; i++) { if (domain_is_routing(searches[i])) continue; - if (!domain_is_valid(searches[i], FALSE)) + if (!domain_is_valid(searches[i], FALSE, TRUE)) continue; add_string_item(rc->searches, searches[i], TRUE); } @@ -2111,11 +2139,16 @@ nm_dns_manager_set_hostname(NMDnsManager *self, const char *hostname, gboolean s * specified, this makes a good default.) However, if the * hostname is the top level of a domain (eg, "example.com"), * then use the hostname itself as the search (since the user - * is unlikely to want "com" as a search domain).a + * is unlikely to want "com" as a search domain). + * + * Because that logic only applies to public domains, the + * "assume_any_tld_is_public" parameter is FALSE. For + * example, it is likely that the user *does* want "local" + * or "localdomain" as a search domain. */ - if (domain_is_valid(domain, TRUE)) { + if (domain_is_valid(domain, TRUE, FALSE)) { /* pass */ - } else if (domain_is_valid(hostname, TRUE)) { + } else if (domain_is_valid(hostname, TRUE, FALSE)) { domain = hostname; } @@ -2124,8 +2157,10 @@ nm_dns_manager_set_hostname(NMDnsManager *self, const char *hostname, gboolean s } } - if (!nm_strdup_reset(&priv->hostdomain, domain)) + if (!nm_strdup_reset(&priv->hostdomain, domain)) { + _LOGT("Established |%s| as host domain.", priv->hostdomain); return; + } if (skip_update) return; |