diff options
Diffstat (limited to 'src/network/networkd-dns.c')
-rw-r--r-- | src/network/networkd-dns.c | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/src/network/networkd-dns.c b/src/network/networkd-dns.c new file mode 100644 index 0000000..7078419 --- /dev/null +++ b/src/network/networkd-dns.c @@ -0,0 +1,294 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "dns-domain.h" +#include "hostname-util.h" +#include "networkd-dns.h" +#include "networkd-manager.h" +#include "networkd-network.h" +#include "parse-util.h" +#include "string-table.h" + +UseDomains link_get_use_domains(Link *link, NetworkConfigSource proto) { + UseDomains n, c, m; + + assert(link); + assert(link->manager); + + if (!link->network) + return USE_DOMAINS_NO; + + switch (proto) { + case NETWORK_CONFIG_SOURCE_DHCP4: + n = link->network->dhcp_use_domains; + c = link->network->compat_dhcp_use_domains; + m = link->manager->dhcp_use_domains; + break; + case NETWORK_CONFIG_SOURCE_DHCP6: + n = link->network->dhcp6_use_domains; + c = link->network->compat_dhcp_use_domains; + m = link->manager->dhcp6_use_domains; + break; + case NETWORK_CONFIG_SOURCE_NDISC: + n = link->network->ndisc_use_domains; + c = _USE_DOMAINS_INVALID; + m = link->manager->ndisc_use_domains; + break; + default: + assert_not_reached(); + } + + /* If per-network and per-protocol setting is specified, use it. */ + if (n >= 0) + return n; + + /* If compat setting is specified, use it. */ + if (c >= 0) + return c; + + /* If per-network but protocol-independent setting is specified, use it. */ + if (link->network->use_domains >= 0) + return link->network->use_domains; + + /* If global per-protocol setting is specified, use it. */ + if (m >= 0) + return m; + + /* If none of them are specified, use the global protocol-independent value. */ + return link->manager->use_domains; +} + +bool link_get_use_dns(Link *link, NetworkConfigSource proto) { + int n, c; + + assert(link); + + if (!link->network) + return false; + + switch (proto) { + case NETWORK_CONFIG_SOURCE_DHCP4: + n = link->network->dhcp_use_dns; + c = link->network->compat_dhcp_use_dns; + break; + case NETWORK_CONFIG_SOURCE_DHCP6: + n = link->network->dhcp6_use_dns; + c = link->network->compat_dhcp_use_dns; + break; + case NETWORK_CONFIG_SOURCE_NDISC: + n = link->network->ndisc_use_dns; + c = -1; + break; + default: + assert_not_reached(); + } + + /* If per-network and per-protocol setting is specified, use it. */ + if (n >= 0) + return n; + + /* If compat setting is specified, use it. */ + if (c >= 0) + return c; + + /* Otherwise, defaults to yes. */ + return true; +} + +int config_parse_domains( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Network *n = ASSERT_PTR(userdata); + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + if (isempty(rvalue)) { + n->search_domains = ordered_set_free(n->search_domains); + n->route_domains = ordered_set_free(n->route_domains); + return 0; + } + + for (const char *p = rvalue;;) { + _cleanup_free_ char *w = NULL, *normalized = NULL; + const char *domain; + bool is_route; + + r = extract_first_word(&p, &w, NULL, 0); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to extract search or route domain, ignoring: %s", rvalue); + return 0; + } + if (r == 0) + return 0; + + is_route = w[0] == '~'; + domain = is_route ? w + 1 : w; + + if (dns_name_is_root(domain) || streq(domain, "*")) { + /* If the root domain appears as is, or the special token "*" is found, we'll + * consider this as routing domain, unconditionally. */ + is_route = true; + domain = "."; /* make sure we don't allow empty strings, thus write the root + * domain as "." */ + } else { + r = dns_name_normalize(domain, 0, &normalized); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "'%s' is not a valid domain name, ignoring.", domain); + continue; + } + + domain = normalized; + + if (is_localhost(domain)) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "'localhost' domain may not be configured as search or route domain, ignoring assignment: %s", + domain); + continue; + } + } + + OrderedSet **set = is_route ? &n->route_domains : &n->search_domains; + r = ordered_set_put_strdup(set, domain); + if (r == -EEXIST) + continue; + if (r < 0) + return log_oom(); + } +} + +int config_parse_dns( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Network *n = ASSERT_PTR(userdata); + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + if (isempty(rvalue)) { + for (unsigned i = 0; i < n->n_dns; i++) + in_addr_full_free(n->dns[i]); + n->dns = mfree(n->dns); + n->n_dns = 0; + return 0; + } + + for (const char *p = rvalue;;) { + _cleanup_(in_addr_full_freep) struct in_addr_full *dns = NULL; + _cleanup_free_ char *w = NULL; + struct in_addr_full **m; + + r = extract_first_word(&p, &w, NULL, 0); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Invalid syntax, ignoring: %s", rvalue); + return 0; + } + if (r == 0) + return 0; + + r = in_addr_full_new_from_string(w, &dns); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to parse dns server address, ignoring: %s", w); + continue; + } + + if (IN_SET(dns->port, 53, 853)) + dns->port = 0; + + m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_full*)); + if (!m) + return log_oom(); + + m[n->n_dns++] = TAKE_PTR(dns); + n->dns = m; + } +} + +int config_parse_dnssec_negative_trust_anchors( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Set **nta = ASSERT_PTR(data); + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + if (isempty(rvalue)) { + *nta = set_free_free(*nta); + return 0; + } + + for (const char *p = rvalue;;) { + _cleanup_free_ char *w = NULL; + + r = extract_first_word(&p, &w, NULL, 0); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to extract negative trust anchor domain, ignoring: %s", rvalue); + return 0; + } + if (r == 0) + return 0; + + r = dns_name_is_valid(w); + if (r <= 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "%s is not a valid domain name, ignoring.", w); + continue; + } + + r = set_ensure_consume(nta, &dns_name_hash_ops, TAKE_PTR(w)); + if (r < 0) + return log_oom(); + } +} + +static const char* const use_domains_table[_USE_DOMAINS_MAX] = { + [USE_DOMAINS_NO] = "no", + [USE_DOMAINS_ROUTE] = "route", + [USE_DOMAINS_YES] = "yes", +}; + +DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(use_domains, UseDomains, USE_DOMAINS_YES); +DEFINE_CONFIG_PARSE_ENUM(config_parse_use_domains, use_domains, UseDomains, "Failed to parse UseDomains=") |