diff options
-rw-r--r-- | man/systemd.network.xml | 24 | ||||
-rw-r--r-- | src/basic/strv.c | 31 | ||||
-rw-r--r-- | src/basic/strv.h | 2 | ||||
-rw-r--r-- | src/libsystemd/sd-network/sd-network.c | 32 | ||||
-rw-r--r-- | src/network/networkctl.c | 45 | ||||
-rw-r--r-- | src/network/networkd-link.c | 49 | ||||
-rw-r--r-- | src/network/networkd-manager.c | 21 | ||||
-rw-r--r-- | src/network/networkd-network-gperf.gperf | 2 | ||||
-rw-r--r-- | src/network/networkd-network.c | 112 | ||||
-rw-r--r-- | src/network/networkd-network.h | 3 | ||||
-rw-r--r-- | src/resolve/resolved-link.c | 2 | ||||
-rw-r--r-- | src/resolve/resolved-manager.h | 1 | ||||
-rw-r--r-- | src/systemd/sd-network.h | 18 |
13 files changed, 199 insertions, 143 deletions
diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 5a6383cfc2..be88d66072 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -396,21 +396,37 @@ described in <citerefentry project='man-pages'><refentrytitle>inet_pton</refentrytitle><manvolnum>3</manvolnum></citerefentry>. This option may be specified more than once. This setting is read by - <citerefentry><refentrytitle>systemd-resolved.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></para> + <citerefentry><refentrytitle>systemd-resolved.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para> </listitem> </varlistentry> <varlistentry> <term><varname>Domains=</varname></term> <listitem> - <para>The domains used for DNS resolution over this link. This setting is read by - <citerefentry><refentrytitle>systemd-resolved.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></para> + <para>The domains used for DNS host name resolution on this link. Takes a list of DNS domain names which + are used as search suffixes for extending single-label host names (host names containing no dots) to become + fully qualified domain names (FQDNs). If a single-label host name is resolved on this interface, each of + the specified search domains are appended to it in turn, converting it into a fully qualified domain name, + until one of them may be successfully resolved.</para> + + <para>The specified domains are also used for routing of DNS queries: look-ups for host names ending in the + domains specified here are preferably routed to the DNS servers configured for this interface. If a domain + name is prefixed with <literal>~</literal>, the domain name becomes a pure "routing" domain, is used for + DNS query routing purposes only and is not used in the described domain search logic. By specifying a + routing domain of <literal>~.</literal> (the tilda indicating definition of a routing domain, the dot + referring to the DNS root domain which is the implied suffix of all valid DNS names) it is possible to + route all DNS traffic preferably to the DNS server specified for this interface. The route domain logic is + particularly useful on multi-homed hosts with DNS servers serving particular private DNS zones on each + interface.</para> + + <para>This setting is read by + <citerefentry><refentrytitle>systemd-resolved.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para> </listitem> </varlistentry> <varlistentry> <term><varname>NTP=</varname></term> <listitem> <para>An NTP server address. This option may be specified more than once. This setting is read by - <citerefentry><refentrytitle>systemd-timesyncd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></para> + <citerefentry><refentrytitle>systemd-timesyncd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para> </listitem> </varlistentry> <varlistentry> diff --git a/src/basic/strv.c b/src/basic/strv.c index 0a3d15706f..dc5bafcf24 100644 --- a/src/basic/strv.c +++ b/src/basic/strv.c @@ -871,3 +871,34 @@ rollback: nl[k] = NULL; return -ENOMEM; } + +int fputstrv(FILE *f, char **l, const char *separator, bool *space) { + bool b = false; + char **s; + int r; + + /* Like fputs(), but for strv, and with a less stupid argument order */ + + if (!f) + f = stdout; + if (!separator) + separator = " "; + if (!space) + space = &b; + + STRV_FOREACH(s, l) { + if (*space) { + r = fputs(separator, f); + if (r < 0) + return r; + } + + r = fputs(*s, f); + if (r < 0) + return r; + + *space = true; + } + + return 0; +} diff --git a/src/basic/strv.h b/src/basic/strv.h index bb61db2638..560f90115c 100644 --- a/src/basic/strv.h +++ b/src/basic/strv.h @@ -169,3 +169,5 @@ char ***strv_free_free(char ***l); char **strv_skip(char **l, size_t n); int strv_extend_n(char ***l, const char *value, size_t n); + +int fputstrv(FILE *f, char **l, const char *separator, bool *space); diff --git a/src/libsystemd/sd-network/sd-network.c b/src/libsystemd/sd-network/sd-network.c index c1f5867ee4..4b7fad9c81 100644 --- a/src/libsystemd/sd-network/sd-network.c +++ b/src/libsystemd/sd-network/sd-network.c @@ -95,10 +95,14 @@ _public_ int sd_network_get_ntp(char ***ret) { return network_get_strv("NTP", ret); } -_public_ int sd_network_get_domains(char ***ret) { +_public_ int sd_network_get_search_domains(char ***ret) { return network_get_strv("DOMAINS", ret); } +_public_ int sd_network_get_route_domains(char ***ret) { + return network_get_strv("ROUTE_DOMAINS", ret); +} + static int network_link_get_string(int ifindex, const char *field, char **ret) { _cleanup_free_ char *s = NULL, *p = NULL; int r; @@ -222,10 +226,14 @@ _public_ int sd_network_link_get_ntp(int ifindex, char ***ret) { return network_link_get_strv(ifindex, "NTP", ret); } -_public_ int sd_network_link_get_domains(int ifindex, char ***ret) { +_public_ int sd_network_link_get_search_domains(int ifindex, char ***ret) { return network_link_get_strv(ifindex, "DOMAINS", ret); } +_public_ int sd_network_link_get_route_domains(int ifindex, char ***ret) { + return network_link_get_strv(ifindex, "ROUTE_DOMAINS", ret); +} + _public_ int sd_network_link_get_carrier_bound_to(int ifindex, char ***ret) { return network_link_get_strv(ifindex, "CARRIER_BOUND_TO", ret); } @@ -234,26 +242,6 @@ _public_ int sd_network_link_get_carrier_bound_by(int ifindex, char ***ret) { return network_link_get_strv(ifindex, "CARRIER_BOUND_BY", ret); } -_public_ int sd_network_link_get_wildcard_domain(int ifindex) { - _cleanup_free_ char *p = NULL, *s = NULL; - int r; - - assert_return(ifindex > 0, -EINVAL); - - if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0) - return -ENOMEM; - - r = parse_env_file(p, NEWLINE, "WILDCARD_DOMAIN", &s, NULL); - if (r == -ENOENT) - return -ENODATA; - if (r < 0) - return r; - if (isempty(s)) - return -ENODATA; - - return parse_boolean(s); -} - static inline int MONITOR_TO_FD(sd_network_monitor *m) { return (int) (unsigned long) m - 1; } diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 4a8fa4d8f3..c710ecda61 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -502,7 +502,7 @@ static int link_status_one( sd_netlink *rtnl, sd_hwdb *hwdb, const char *name) { - _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL; + _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains = NULL; _cleanup_free_ char *setup_state = NULL, *operational_state = NULL, *tz = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; _cleanup_(sd_device_unrefp) sd_device *d = NULL; @@ -576,18 +576,8 @@ static int link_status_one( setup_state_to_color(setup_state, &on_color_setup, &off_color_setup); sd_network_link_get_dns(ifindex, &dns); - sd_network_link_get_domains(ifindex, &domains); - r = sd_network_link_get_wildcard_domain(ifindex); - if (r > 0) { - char *wildcard; - - wildcard = strdup("*"); - if (!wildcard) - return log_oom(); - - if (strv_consume(&domains, wildcard) < 0) - return log_oom(); - } + sd_network_link_get_search_domains(ifindex, &search_domains); + sd_network_link_get_route_domains(ifindex, &route_domains); sprintf(devid, "n%i", ifindex); @@ -655,8 +645,10 @@ static int link_status_one( if (!strv_isempty(dns)) dump_list(" DNS: ", dns); - if (!strv_isempty(domains)) - dump_list(" Domain: ", domains); + if (!strv_isempty(search_domains)) + dump_list(" Search Domains: ", search_domains); + if (!strv_isempty(route_domains)) + dump_list(" Route Domains: ", route_domains); (void) sd_network_link_get_ntp(ifindex, &ntp); if (!strv_isempty(ntp)) @@ -691,30 +683,35 @@ static int link_status(int argc, char *argv[], void *userdata) { if (argc <= 1 && !arg_all) { _cleanup_free_ char *operational_state = NULL; - _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL; + _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains; const char *on_color_operational, *off_color_operational; sd_network_get_operational_state(&operational_state); operational_state_to_color(operational_state, &on_color_operational, &off_color_operational); - printf("%s%s%s State: %s%s%s\n", + printf("%s%s%s State: %s%s%s\n", on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, on_color_operational, strna(operational_state), off_color_operational); - dump_addresses(rtnl, " Address: ", 0); - dump_gateways(rtnl, hwdb, " Gateway: ", 0); + dump_addresses(rtnl, " Address: ", 0); + dump_gateways(rtnl, hwdb, " Gateway: ", 0); sd_network_get_dns(&dns); if (!strv_isempty(dns)) - dump_list(" DNS: ", dns); + dump_list(" DNS: ", dns); + + sd_network_get_search_domains(&search_domains); + if (!strv_isempty(search_domains)) + dump_list("Search Domains: ", search_domains); + + sd_network_get_route_domains(&route_domains); + if (!strv_isempty(route_domains)) + dump_list(" Route Domains: ", route_domains); - sd_network_get_domains(&domains); - if (!strv_isempty(domains)) - dump_list(" Domain: ", domains); sd_network_get_ntp(&ntp); if (!strv_isempty(ntp)) - dump_list(" NTP: ", ntp); + dump_list(" NTP: ", ntp); return 0; } diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index bbda691c08..c152ec3cf6 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2729,7 +2729,6 @@ int link_save(Link *link) { admin_state, oper_state); if (link->network) { - char **address, **domain; bool space; sd_dhcp6_lease *dhcp6_lease = NULL; @@ -2743,12 +2742,7 @@ int link_save(Link *link) { fputs("DNS=", f); space = false; - STRV_FOREACH(address, link->network->dns) { - if (space) - fputc(' ', f); - fputs(*address, f); - space = true; - } + fputstrv(f, link->network->dns, NULL, &space); if (link->network->dhcp_dns && link->dhcp_lease) { @@ -2778,12 +2772,7 @@ int link_save(Link *link) { fputs("NTP=", f); space = false; - STRV_FOREACH(address, link->network->ntp) { - if (space) - fputc(' ', f); - fputs(*address, f); - space = true; - } + fputstrv(f, link->network->ntp, NULL, &space); if (link->network->dhcp_ntp && link->dhcp_lease) { @@ -2801,7 +2790,6 @@ int link_save(Link *link) { if (link->network->dhcp_ntp && dhcp6_lease) { struct in6_addr *in6_addrs; char **hosts; - char **hostname; r = sd_dhcp6_lease_get_ntp_addrs(dhcp6_lease, &in6_addrs); @@ -2813,26 +2801,14 @@ int link_save(Link *link) { } r = sd_dhcp6_lease_get_ntp_fqdn(dhcp6_lease, &hosts); - if (r > 0) { - STRV_FOREACH(hostname, hosts) { - if (space) - fputc(' ', f); - fputs(*hostname, f); - space = true; - } - } + if (r > 0) + fputstrv(f, hosts, NULL, &space); } fputc('\n', f); fputs("DOMAINS=", f); - space = false; - STRV_FOREACH(domain, link->network->domains) { - if (space) - fputc(' ', f); - fputs(*domain, f); - space = true; - } + fputstrv(f, link->network->search_domains, NULL, &space); if (link->network->dhcp_domains && link->dhcp_lease) { @@ -2851,20 +2827,15 @@ int link_save(Link *link) { char **domains; r = sd_dhcp6_lease_get_domains(dhcp6_lease, &domains); - if (r >= 0) { - STRV_FOREACH(domain, domains) { - if (space) - fputc(' ', f); - fputs(*domain, f); - space = true; - } - } + if (r >= 0) + fputstrv(f, domains, NULL, &space); } fputc('\n', f); - fprintf(f, "WILDCARD_DOMAIN=%s\n", - yes_no(link->network->wildcard_domain)); + fputs("ROUTE_DOMAINS=", f); + fputstrv(f, link->network->route_domains, NULL, NULL); + fputc('\n', f); fprintf(f, "LLMNR=%s\n", resolve_support_to_string(link->network->llmnr)); diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 24f5304cb0..7392f4758d 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -830,7 +830,7 @@ static void print_string_set(FILE *f, const char *field, Set *s) { } static int manager_save(Manager *m) { - _cleanup_set_free_free_ Set *dns = NULL, *ntp = NULL, *domains = NULL; + _cleanup_set_free_free_ Set *dns = NULL, *ntp = NULL, *search_domains = NULL, *route_domains = NULL; Link *link; Iterator i; _cleanup_free_ char *temp_path = NULL; @@ -851,8 +851,12 @@ static int manager_save(Manager *m) { if (!ntp) return -ENOMEM; - domains = set_new(&string_hash_ops); - if (!domains) + search_domains = set_new(&string_hash_ops); + if (!search_domains) + return -ENOMEM; + + route_domains = set_new(&string_hash_ops); + if (!route_domains) return -ENOMEM; HASHMAP_FOREACH(link, m->links, i) { @@ -874,7 +878,11 @@ static int manager_save(Manager *m) { if (r < 0) return r; - r = set_put_strdupv(domains, link->network->domains); + r = set_put_strdupv(search_domains, link->network->search_domains); + if (r < 0) + return r; + + r = set_put_strdupv(route_domains, link->network->route_domains); if (r < 0) return r; @@ -911,7 +919,7 @@ static int manager_save(Manager *m) { r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname); if (r >= 0) { - r = set_put_strdup(domains, domainname); + r = set_put_strdup(search_domains, domainname); if (r < 0) return r; } else if (r != -ENODATA) @@ -934,7 +942,8 @@ static int manager_save(Manager *m) { print_string_set(f, "DNS=", dns); print_string_set(f, "NTP=", ntp); - print_string_set(f, "DOMAINS=", domains); + print_string_set(f, "DOMAINS=", search_domains); + print_string_set(f, "ROUTE_DOMAINS=", route_domains); r = fflush_and_check(f); if (r < 0) diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 2f2a36ccca..325aac7a61 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -43,7 +43,7 @@ Network.IPv6Token, config_parse_ipv6token, Network.LLDP, config_parse_bool, 0, offsetof(Network, lldp) Network.Address, config_parse_address, 0, 0 Network.Gateway, config_parse_gateway, 0, 0 -Network.Domains, config_parse_domains, 0, offsetof(Network, domains) +Network.Domains, config_parse_domains, 0, 0 Network.DNS, config_parse_strv, 0, offsetof(Network, dns) Network.LLMNR, config_parse_resolve_support, 0, offsetof(Network, llmnr) Network.MulticastDNS, config_parse_resolve_support, 0, offsetof(Network, mdns) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index c11cb3dcb3..1e520062f4 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -233,7 +233,8 @@ void network_free(Network *network) { strv_free(network->ntp); strv_free(network->dns); - strv_free(network->domains); + strv_free(network->search_domains); + strv_free(network->route_domains); strv_free(network->bind_carrier); netdev_unref(network->bridge); @@ -384,7 +385,10 @@ int network_apply(Manager *manager, Network *network, Link *link) { route->protocol = RTPROT_STATIC; } - if (network->dns || network->ntp || network->domains) { + if (!strv_isempty(network->dns) || + !strv_isempty(network->ntp) || + !strv_isempty(network->search_domains) || + !strv_isempty(network->route_domains)) { manager_dirty(manager); link_dirty(link); } @@ -469,49 +473,85 @@ int config_parse_netdev(const char *unit, return 0; } -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 *network = userdata; - char ***domains = data; - char **domain; +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) { + + const char *p; + Network *n = data; int r; - r = config_parse_strv(unit, filename, line, section, section_line, - lvalue, ltype, rvalue, domains, userdata); - if (r < 0) - return r; + assert(n); + assert(lvalue); + assert(rvalue); - strv_uniq(*domains); - network->wildcard_domain = !!strv_find(*domains, "*"); + if (isempty(rvalue)) { + n->search_domains = strv_free(n->search_domains); + n->route_domains = strv_free(n->route_domains); + return 0; + } - STRV_FOREACH(domain, *domains) { - if (is_localhost(*domain)) - log_syntax(unit, LOG_ERR, filename, line, 0, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain); - else { - r = dns_name_is_valid(*domain); - if (r <= 0 && !streq(*domain, "*")) { - if (r < 0) - log_error_errno(r, "Failed to validate domain name: %s: %m", *domain); - if (r == 0) - log_warning("Domain name is not valid, ignoring assignment: %s", *domain); - } else + p = rvalue; + for (;;) { + _cleanup_free_ char *w = NULL, *normalized = NULL; + const char *domain; + bool is_route; + + r = extract_first_word(&p, &w, NULL, 0); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract search or route domain, ignoring: %s", rvalue); + break; + } + if (r == 0) + break; + + 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, &normalized); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "'%s' is not a valid domain name, ignoring.", domain); + continue; + } + + domain = normalized; + + if (is_localhost(domain)) { + log_syntax(unit, LOG_ERR, filename, line, 0, "'localhost' domain names may not be configure as search or route domains, ignoring assignment: %s", domain); continue; + } } - strv_remove(*domains, *domain); + if (is_route) { + r = strv_extend(&n->route_domains, domain); + if (r < 0) + return log_oom(); - /* We removed one entry, make sure we don't skip the next one */ - domain--; + } else { + r = strv_extend(&n->search_domains, domain); + if (r < 0) + return log_oom(); + } } + strv_uniq(n->route_domains); + strv_uniq(n->search_domains); + return 0; } @@ -930,7 +970,7 @@ int config_parse_dnssec_negative_trust_anchors( Network *n = data; int r; - assert(filename); + assert(n); assert(lvalue); assert(rvalue); diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index b07fa41abc..d17093d384 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -141,8 +141,7 @@ struct Network { Hashmap *routes_by_section; Hashmap *fdb_entries_by_section; - bool wildcard_domain; - char **domains, **dns, **ntp, **bind_carrier; + char **search_domains, **route_domains, **dns, **ntp, **bind_carrier; ResolveSupport llmnr; ResolveSupport mdns; diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c index e2f9c8b400..8f0afc185b 100644 --- a/src/resolve/resolved-link.c +++ b/src/resolve/resolved-link.c @@ -384,7 +384,7 @@ static int link_update_search_domains(Link *l) { assert(l); - r = sd_network_link_get_domains(l->ifindex, &domains); + r = sd_network_link_get_search_domains(l->ifindex, &domains); if (r == -ENODATA) { /* networkd knows nothing about this interface, and that's fine. */ r = 0; diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h index a4291d57ff..1af49c8fb9 100644 --- a/src/resolve/resolved-manager.h +++ b/src/resolve/resolved-manager.h @@ -74,6 +74,7 @@ struct Manager { LIST_HEAD(DnsSearchDomain, search_domains); unsigned n_search_domains; + bool permit_domain_search; bool need_builtin_fallbacks:1; diff --git a/src/systemd/sd-network.h b/src/systemd/sd-network.h index 653c61a162..ff0d2b191e 100644 --- a/src/systemd/sd-network.h +++ b/src/systemd/sd-network.h @@ -64,8 +64,11 @@ int sd_network_get_dns(char ***dns); * representations of IP addresses */ int sd_network_get_ntp(char ***ntp); -/* Get the search/routing domains for all links. */ -int sd_network_get_domains(char ***domains); +/* Get the search domains for all links. */ +int sd_network_get_search_domains(char ***domains); + +/* Get the search domains for all links. */ +int sd_network_get_route_domains(char ***domains); /* Get setup state from ifindex. * Possible states: @@ -134,8 +137,11 @@ int sd_network_link_get_dnssec_negative_trust_anchors(int ifindex, char ***nta); int sd_network_link_get_lldp(int ifindex, char **lldp); -/* Get the DNS domain names for a given link. */ -int sd_network_link_get_domains(int ifindex, char ***domains); +/* Get the search DNS domain names for a given link. */ +int sd_network_link_get_search_domains(int ifindex, char ***domains); + +/* Get the route DNS domain names for a given link. */ +int sd_network_link_get_route_domains(int ifindex, char ***domains); /* Get the CARRIERS to which current link is bound to. */ int sd_network_link_get_carrier_bound_to(int ifindex, char ***carriers); @@ -146,10 +152,6 @@ int sd_network_link_get_carrier_bound_by(int ifindex, char ***carriers); /* Get the timezone that was learnt on a specific link. */ int sd_network_link_get_timezone(int ifindex, char **timezone); -/* Returns whether or not domains that don't match any link should be resolved - * on this link. 1 for yes, 0 for no and negative value for error */ -int sd_network_link_get_wildcard_domain(int ifindex); - /* Monitor object */ typedef struct sd_network_monitor sd_network_monitor; |