diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 1492f2032a..1bff564d59 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -1926,15 +1926,14 @@ EmitDNS= DNS= - DNS= specifies a list of recursive - DNS server IPv6 addresses that distributed via Router Advertisement - messages when EmitDNS= is true. If DNS= - is empty, DNS servers are read from the - [Network] section. If the - [Network] section does not contain any DNS servers - either, DNS servers from the uplink with the highest priority default - route are used. When EmitDNS= is false, no DNS server - information is sent in Router Advertisement messages. + DNS= specifies a list of recursive DNS server IPv6 addresses + that are distributed via Router Advertisement messages when EmitDNS= is + true. DNS= also takes special value _link_local; in that + case the IPv6 link local address is distributed. If DNS= is empty, DNS + servers are read from the [Network] section. If the + [Network] section does not contain any DNS servers either, DNS servers from + the uplink with the highest priority default route are used. When EmitDNS= + is false, no DNS server information is sent in Router Advertisement messages. EmitDNS= defaults to true. diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index f3744e2354..cfecf76a79 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1514,6 +1514,10 @@ static int link_acquire_ipv6_conf(Link *link) { log_link_debug(link, "Starting IPv6 Router Advertisements"); + r = radv_emit_dns(link); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to configure DNS or Domains in IPv6 Router Advertisement: %m"); + r = sd_radv_start(link->radv); if (r < 0 && r != -EBUSY) return log_link_warning_errno(link, r, "Could not start IPv6 Router Advertisement: %m"); diff --git a/src/network/networkd-radv.c b/src/network/networkd-radv.c index d48609f985..620939e251 100644 --- a/src/network/networkd-radv.c +++ b/src/network/networkd-radv.c @@ -443,20 +443,29 @@ static int radv_get_ip6dns(Network *network, struct in6_addr **dns, static int radv_set_dns(Link *link, Link *uplink) { _cleanup_free_ struct in6_addr *dns = NULL; - size_t n_dns; usec_t lifetime_usec; + size_t n_dns; int r; if (!link->network->router_emit_dns) return 0; if (link->network->router_dns) { - dns = newdup(struct in6_addr, link->network->router_dns, - link->network->n_router_dns); + struct in6_addr *p; + + dns = new(struct in6_addr, link->network->n_router_dns); if (!dns) return -ENOMEM; - n_dns = link->network->n_router_dns; + p = dns; + for (size_t i = 0; i < link->network->n_router_dns; i++) + if (IN6_IS_ADDR_UNSPECIFIED(&link->network->router_dns[i])) { + if (!IN6_IS_ADDR_UNSPECIFIED(&link->ipv6ll_address)) + *(p++) = link->ipv6ll_address; + } else + *(p++) = link->network->router_dns[i]; + + n_dns = p - dns; lifetime_usec = link->network->router_dns_lifetime_usec; goto set_dns; @@ -620,7 +629,7 @@ int radv_configure(Link *link) { } - return radv_emit_dns(link); + return 0; } int config_parse_radv_dns( @@ -658,19 +667,30 @@ int config_parse_radv_dns( if (r == 0) break; - if (in_addr_from_string(AF_INET6, w, &a) >= 0) { - struct in6_addr *m; + if (streq(w, "_link_local")) + a = IN_ADDR_NULL; + else { + r = in_addr_from_string(AF_INET6, w, &a); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, + "Failed to parse DNS server address, ignoring: %s", w); + continue; + } - m = reallocarray(n->router_dns, n->n_router_dns + 1, sizeof(struct in6_addr)); - if (!m) - return log_oom(); + if (in_addr_is_null(AF_INET6, &a)) { + log_syntax(unit, LOG_ERR, filename, line, 0, + "DNS server address is null, ignoring: %s", w); + continue; + } + } - m[n->n_router_dns++] = a.in6; - n->router_dns = m; + struct in6_addr *m; + m = reallocarray(n->router_dns, n->n_router_dns + 1, sizeof(struct in6_addr)); + if (!m) + return log_oom(); - } else - log_syntax(unit, LOG_ERR, filename, line, 0, - "Failed to parse DNS server address, ignoring: %s", w); + m[n->n_router_dns++] = a.in6; + n->router_dns = m; } return 0;