diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 0b634572a9..b7743557ec 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -854,28 +854,26 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda static int link_push_dns_to_dhcp_server(Link *link, sd_dhcp_server *s) { _cleanup_free_ struct in_addr *addresses = NULL; size_t n_addresses = 0, n_allocated = 0; - char **a; + unsigned i; log_debug("Copying DNS server information from %s", link->ifname); if (!link->network) return 0; - STRV_FOREACH(a, link->network->dns) { - struct in_addr ia; + for (i = 0; i < link->network->n_dns; i++) { /* Only look for IPv4 addresses */ - if (inet_pton(AF_INET, *a, &ia) <= 0) + if (link->network->dns[i].family != AF_INET) continue; if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + 1)) return log_oom(); - addresses[n_addresses++] = ia; + addresses[n_addresses++] = link->network->dns[i].address.in; } - if (link->network->dhcp_use_dns && - link->dhcp_lease) { + if (link->network->dhcp_use_dns && link->dhcp_lease) { const struct in_addr *da = NULL; int n; @@ -919,8 +917,7 @@ static int link_push_ntp_to_dhcp_server(Link *link, sd_dhcp_server *s) { addresses[n_addresses++] = ia; } - if (link->network->dhcp_use_ntp && - link->dhcp_lease) { + if (link->network->dhcp_use_ntp && link->dhcp_lease) { const struct in_addr *da = NULL; int n; @@ -3235,7 +3232,7 @@ int link_save(Link *link) { if (r < 0) goto fail; - fchmod(fileno(f), 0644); + (void) fchmod(fileno(f), 0644); fprintf(f, "# This is private data. Do not parse.\n" @@ -3248,6 +3245,7 @@ int link_save(Link *link) { sd_dhcp6_lease *dhcp6_lease = NULL; const char *dhcp_domainname = NULL; char **dhcp6_domains = NULL; + unsigned j; if (link->dhcp6_client) { r = sd_dhcp6_client_get_lease(link->dhcp6_client, &dhcp6_lease); @@ -3259,7 +3257,22 @@ int link_save(Link *link) { fputs("DNS=", f); space = false; - fputstrv(f, link->network->dns, NULL, &space); + + for (j = 0; j < link->network->n_dns; j++) { + _cleanup_free_ char *b = NULL; + + r = in_addr_to_string(link->network->dns[j].family, + &link->network->dns[j].address, &b); + if (r < 0) { + log_debug_errno(r, "Failed to format address, ignoring: %m"); + continue; + } + + if (space) + fputc(' ', f); + fputs(b, f); + space = true; + } if (link->network->dhcp_use_dns && link->dhcp_lease) { diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index a1252c9b51..c3d3f48a3f 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -774,11 +774,48 @@ static int manager_connect_rtnl(Manager *m) { return 0; } -static int ordered_set_put_in_addr(OrderedSet *s, const struct in_addr *address) { +static int ordered_set_put_in_addr_data(OrderedSet *s, const struct in_addr_data *address) { char *p; int r; assert(s); + assert(address); + + r = in_addr_to_string(address->family, &address->address, &p); + if (r < 0) + return r; + + r = ordered_set_consume(s, p); + if (r == -EEXIST) + return 0; + + return r; +} + +static int ordered_set_put_in_addr_datav(OrderedSet *s, const struct in_addr_data *addresses, unsigned n) { + int r, c = 0; + unsigned i; + + assert(s); + assert(addresses || n == 0); + + for (i = 0; i < n; i++) { + r = ordered_set_put_in_addr_data(s, addresses+i); + if (r < 0) + return r; + + c += r; + } + + return c; +} + +static int ordered_set_put_in4_addr(OrderedSet *s, const struct in_addr *address) { + char *p; + int r; + + assert(s); + assert(address); r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p); if (r < 0) @@ -791,14 +828,15 @@ static int ordered_set_put_in_addr(OrderedSet *s, const struct in_addr *address) return r; } -static int ordered_set_put_in_addrv(OrderedSet *s, const struct in_addr *addresses, int n) { - int r, i, c = 0; +static int ordered_set_put_in4_addrv(OrderedSet *s, const struct in_addr *addresses, unsigned n) { + int r, c = 0; + unsigned i; assert(s); - assert(n <= 0 || addresses); + assert(n == 0 || addresses); for (i = 0; i < n; i++) { - r = ordered_set_put_in_addr(s, addresses+i); + r = ordered_set_put_in4_addr(s, addresses+i); if (r < 0) return r; @@ -865,7 +903,7 @@ static int manager_save(Manager *m) { continue; /* First add the static configured entries */ - r = ordered_set_put_strdupv(dns, link->network->dns); + r = ordered_set_put_in_addr_datav(dns, link->network->dns, link->network->n_dns); if (r < 0) return r; @@ -890,7 +928,7 @@ static int manager_save(Manager *m) { r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses); if (r > 0) { - r = ordered_set_put_in_addrv(dns, addresses, r); + r = ordered_set_put_in4_addrv(dns, addresses, r); if (r < 0) return r; } else if (r < 0 && r != -ENODATA) @@ -902,7 +940,7 @@ static int manager_save(Manager *m) { r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses); if (r > 0) { - r = ordered_set_put_in_addrv(ntp, addresses, r); + r = ordered_set_put_in4_addrv(ntp, addresses, r); if (r < 0) return r; } else if (r < 0 && r != -ENODATA) @@ -934,7 +972,7 @@ static int manager_save(Manager *m) { if (r < 0) return r; - fchmod(fileno(f), 0644); + (void) fchmod(fileno(f), 0644); fprintf(f, "# This is private data. Do not parse.\n" diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index e3a77c2152..bc4dc95ff9 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -244,7 +244,7 @@ void network_free(Network *network) { free(network->mac); strv_free(network->ntp); - strv_free(network->dns); + free(network->dns); strv_free(network->search_domains); strv_free(network->route_domains); strv_free(network->bind_carrier); @@ -396,7 +396,7 @@ int network_apply(Network *network, Link *link) { route->protocol = RTPROT_STATIC; } - if (!strv_isempty(network->dns) || + if (network->n_dns > 0 || !strv_isempty(network->ntp) || !strv_isempty(network->search_domains) || !strv_isempty(network->route_domains)) @@ -1004,29 +1004,35 @@ int config_parse_dns( for (;;) { _cleanup_free_ char *w = NULL; union in_addr_union a; + struct in_addr_data *m; int family; - r = extract_first_word(&rvalue, &w, NULL, EXTRACT_QUOTES|EXTRACT_RETAIN_ESCAPE); - if (r == 0) - break; + r = extract_first_word(&rvalue, &w, NULL, 0); if (r == -ENOMEM) return log_oom(); if (r < 0) { log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue); break; } + if (r == 0) + break; r = in_addr_from_string_auto(w, &family, &a); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse dns server address, ignoring: %s", w); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse dns server address, ignoring: %s", w); continue; } - r = strv_consume(&n->dns, w); - if (r < 0) + m = realloc(n->dns, (n->n_dns + 1) * sizeof(struct in_addr_data)); + if (!m) return log_oom(); - w = NULL; + m[n->n_dns++] = (struct in_addr_data) { + .family = family, + .address = a, + }; + + n->dns = m; } return 0; diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 735d7f7a77..17cff956da 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -194,7 +194,10 @@ struct Network { Hashmap *routes_by_section; Hashmap *fdb_entries_by_section; - char **search_domains, **route_domains, **dns, **ntp, **bind_carrier; + struct in_addr_data *dns; + unsigned n_dns; + + char **search_domains, **route_domains, **ntp, **bind_carrier; ResolveSupport llmnr; ResolveSupport mdns;