]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: also save NTP servers and friends obtained by other protocols
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 8 Oct 2023 04:06:25 +0000 (13:06 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 8 Oct 2023 04:06:28 +0000 (13:06 +0900)
Previously, only servers that statically configursd or obtained by
DHCPv4 protocol are saved in the manager state file.

NTP servers obtained by DHCPv6 could not be used by timesyncd.

Fixes #29148.

src/network/networkd-state-file.c

index 85c9d2108204d391a95122a8cdc0b950d64b052e..03146c62c7f98a44d3219067c7f11b5aede96063 100644 (file)
 #include "strv.h"
 #include "tmpfile-util.h"
 
-static int ordered_set_put_dns_server(OrderedSet **s, int ifindex, struct in_addr_full *dns) {
-        const char *p;
+static int ordered_set_put_dns_servers(OrderedSet **s, int ifindex, struct in_addr_full **dns, unsigned n) {
         int r;
 
         assert(s);
-        assert(dns);
+        assert(dns || n == 0);
 
-        if (dns->ifindex != 0 && dns->ifindex != ifindex)
-                return 0;
+        FOREACH_ARRAY(a, dns, n) {
+                const char *p;
 
-        p = in_addr_full_to_string(dns);
-        if (!p)
-                return 0;
+                if ((*a)->ifindex != 0 && (*a)->ifindex != ifindex)
+                        return 0;
 
-        r = ordered_set_put_strdup(s, p);
-        if (r == -EEXIST)
-                return 0;
+                p = in_addr_full_to_string(*a);
+                if (!p)
+                        return 0;
+
+                r = ordered_set_put_strdup(s, p);
+                if (r < 0)
+                        return r;
+        }
 
-        return r;
+        return 0;
 }
 
-static int ordered_set_put_dns_servers(OrderedSet **s, int ifindex, struct in_addr_full **dns, unsigned n) {
-        int r, c = 0;
+static int ordered_set_put_in4_addrv(
+                OrderedSet **s,
+                const struct in_addr *addresses,
+                size_t n,
+                bool (*predicate)(const struct in_addr *addr)) {
+
+        int r;
 
         assert(s);
-        assert(dns || n == 0);
+        assert(n == 0 || addresses);
+
+        FOREACH_ARRAY(a, addresses, n) {
+                if (predicate && !predicate(a))
+                        continue;
 
-        for (unsigned i = 0; i < n; i++) {
-                r = ordered_set_put_dns_server(s, ifindex, dns[i]);
+                r = ordered_set_put_strdup(s, IN4_ADDR_TO_STRING(a));
                 if (r < 0)
                         return r;
+        }
+
+        return 0;
+}
 
-                c += r;
+static int ordered_set_put_in6_addrv(
+                OrderedSet **s,
+                const struct in6_addr *addresses,
+                size_t n) {
+
+        int r;
+
+        assert(s);
+        assert(n == 0 || addresses);
+
+        FOREACH_ARRAY(a, addresses, n) {
+                r = ordered_set_put_strdup(s, IN6_ADDR_TO_STRING(a));
+                if (r < 0)
+                        return r;
         }
 
-        return c;
+        return 0;
 }
 
-static int ordered_set_put_in4_addr(OrderedSet **s, const struct in_addr *address) {
-        _cleanup_free_ char *p = NULL;
+static int link_put_dns(Link *link, OrderedSet **s) {
         int r;
 
+        assert(link);
+        assert(link->network);
         assert(s);
-        assert(address);
 
-        r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p);
+        if (link->n_dns != UINT_MAX)
+                return ordered_set_put_dns_servers(s, link->ifindex, link->dns, link->n_dns);
+
+        r = ordered_set_put_dns_servers(s, link->ifindex, link->network->dns, link->network->n_dns);
         if (r < 0)
                 return r;
 
-        r = ordered_set_ensure_allocated(s, &string_hash_ops_free);
+        if (link->dhcp_lease && link->network->dhcp_use_dns) {
+                const struct in_addr *addresses;
+
+                r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
+                if (r >= 0) {
+                        r = ordered_set_put_in4_addrv(s, addresses, r, in4_addr_is_non_local);
+                        if (r < 0)
+                                return r;
+                }
+        }
+
+        if (link->dhcp6_lease && link->network->dhcp6_use_dns) {
+                const struct in6_addr *addresses;
+
+                r = sd_dhcp6_lease_get_dns(link->dhcp6_lease, &addresses);
+                if (r >= 0) {
+                        r = ordered_set_put_in6_addrv(s, addresses, r);
+                        if (r < 0)
+                                return r;
+                }
+        }
+
+        if (link->network->ipv6_accept_ra_use_dns) {
+                NDiscRDNSS *a;
+
+                SET_FOREACH(a, link->ndisc_rdnss) {
+                        r = ordered_set_put_in6_addrv(s, &a->router, 1);
+                        if (r < 0)
+                                return r;
+                }
+        }
+
+        return 0;
+}
+
+static int link_put_ntp(Link *link, OrderedSet **s) {
+        int r;
+
+        assert(link);
+        assert(link->network);
+        assert(s);
+
+        if (link->ntp)
+                return ordered_set_put_strdupv(s, link->ntp);
+
+        r = ordered_set_put_strdupv(s, link->network->ntp);
         if (r < 0)
                 return r;
 
-        r = ordered_set_consume(*s, TAKE_PTR(p));
-        if (r == -EEXIST)
-                return 0;
+        if (link->dhcp_lease && link->network->dhcp_use_ntp) {
+                const struct in_addr *addresses;
 
-        return r;
+                r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
+                if (r >= 0) {
+                        r = ordered_set_put_in4_addrv(s, addresses, r, in4_addr_is_non_local);
+                        if (r < 0)
+                                return r;
+                }
+        }
+
+        if (link->dhcp6_lease && link->network->dhcp6_use_ntp) {
+                const struct in6_addr *addresses;
+                char **fqdn;
+
+                r = sd_dhcp6_lease_get_ntp_addrs(link->dhcp6_lease, &addresses);
+                if (r >= 0) {
+                        r = ordered_set_put_in6_addrv(s, addresses, r);
+                        if (r < 0)
+                                return r;
+                }
+
+                r = sd_dhcp6_lease_get_ntp_fqdn(link->dhcp6_lease, &fqdn);
+                if (r >= 0) {
+                        r = ordered_set_put_strdupv(s, fqdn);
+                        if (r < 0)
+                                return r;
+                }
+        }
+
+        return 0;
 }
 
-static int ordered_set_put_in4_addrv(
-                OrderedSet **s,
-                const struct in_addr *addresses,
-                size_t n,
-                bool (*predicate)(const struct in_addr *addr)) {
+static int link_put_sip(Link *link, OrderedSet **s) {
+        int r;
+
+        assert(link);
+        assert(link->network);
+        assert(s);
+
+        if (link->dhcp_lease && link->network->dhcp_use_ntp) {
+                const struct in_addr *addresses;
 
-        int r, c = 0;
+                r = sd_dhcp_lease_get_sip(link->dhcp_lease, &addresses);
+                if (r >= 0) {
+                        r = ordered_set_put_in4_addrv(s, addresses, r, in4_addr_is_non_local);
+                        if (r < 0)
+                                return r;
+                }
+        }
 
+        return 0;
+}
+
+static int link_put_domains(Link *link, bool is_route, OrderedSet **s) {
+        OrderedSet *link_domains, *network_domains;
+        DHCPUseDomains use_domains;
+        int r;
+
+        assert(link);
+        assert(link->network);
         assert(s);
-        assert(n == 0 || addresses);
 
-        for (size_t i = 0; i < n; i++) {
-                if (predicate && !predicate(&addresses[i]))
-                        continue;
-                r = ordered_set_put_in4_addr(s, addresses+i);
-                if (r < 0)
-                        return r;
+        link_domains = is_route ? link->route_domains : link->search_domains;
+        network_domains = is_route ? link->network->route_domains : link->network->search_domains;
+        use_domains = is_route ? DHCP_USE_DOMAINS_ROUTE : DHCP_USE_DOMAINS_YES;
+
+        if (link_domains)
+                return ordered_set_put_string_set(s, link_domains);
 
-                c += r;
+        r = ordered_set_put_string_set(s, network_domains);
+        if (r < 0)
+                return r;
+
+        if (link->dhcp_lease && link->network->dhcp_use_domains == use_domains) {
+                const char *domainname;
+                char **domains;
+
+                r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
+                if (r >= 0) {
+                        r = ordered_set_put_strdup(s, domainname);
+                        if (r < 0)
+                                return r;
+                }
+
+                r = sd_dhcp_lease_get_search_domains(link->dhcp_lease, &domains);
+                if (r >= 0) {
+                        r = ordered_set_put_strdupv(s, domains);
+                        if (r < 0)
+                                return r;
+                }
+        }
+
+        if (link->dhcp6_lease && link->network->dhcp6_use_domains == use_domains) {
+                char **domains;
+
+                r = sd_dhcp6_lease_get_domains(link->dhcp6_lease, &domains);
+                if (r >= 0) {
+                        r = ordered_set_put_strdupv(s, domains);
+                        if (r < 0)
+                                return r;
+                }
         }
 
-        return c;
+        if (link->network->ipv6_accept_ra_use_domains == use_domains) {
+                NDiscDNSSL *a;
+
+                SET_FOREACH(a, link->ndisc_dnssl) {
+                        r = ordered_set_put_strdup(s, NDISC_DNSSL_DOMAIN(a));
+                        if (r < 0)
+                                return r;
+                }
+        }
+
+        return 0;
 }
 
 int manager_save(Manager *m) {
@@ -126,8 +288,6 @@ int manager_save(Manager *m) {
                 return 0; /* Do not update state file when running in test mode. */
 
         HASHMAP_FOREACH(link, m->links_by_index) {
-                const struct in_addr *addresses;
-
                 if (link->flags & IFF_LOOPBACK)
                         continue;
 
@@ -147,82 +307,25 @@ int manager_save(Manager *m) {
                                 links_online++;
                 }
 
-                /* First add the static configured entries */
-                if (link->n_dns != UINT_MAX)
-                        r = ordered_set_put_dns_servers(&dns, link->ifindex, link->dns, link->n_dns);
-                else
-                        r = ordered_set_put_dns_servers(&dns, link->ifindex, link->network->dns, link->network->n_dns);
+                r = link_put_dns(link, &dns);
                 if (r < 0)
                         return r;
 
-                r = ordered_set_put_strdupv(&ntp, link->ntp ?: link->network->ntp);
+                r = link_put_ntp(link, &ntp);
                 if (r < 0)
                         return r;
 
-                r = ordered_set_put_string_set(&search_domains, link->search_domains ?: link->network->search_domains);
+                r = link_put_sip(link, &sip);
                 if (r < 0)
                         return r;
 
-                r = ordered_set_put_string_set(&route_domains, link->route_domains ?: link->network->route_domains);
+                r = link_put_domains(link, /* is_route = */ false, &search_domains);
                 if (r < 0)
                         return r;
 
-                if (!link->dhcp_lease)
-                        continue;
-
-                /* Secondly, add the entries acquired via DHCP */
-                if (link->network->dhcp_use_dns) {
-                        r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
-                        if (r > 0) {
-                                r = ordered_set_put_in4_addrv(&dns, addresses, r, in4_addr_is_non_local);
-                                if (r < 0)
-                                        return r;
-                        } else if (r < 0 && r != -ENODATA)
-                                return r;
-                }
-
-                if (link->network->dhcp_use_ntp) {
-                        r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
-                        if (r > 0) {
-                                r = ordered_set_put_in4_addrv(&ntp, addresses, r, in4_addr_is_non_local);
-                                if (r < 0)
-                                        return r;
-                        } else if (r < 0 && r != -ENODATA)
-                                return r;
-                }
-
-                if (link->network->dhcp_use_sip) {
-                        r = sd_dhcp_lease_get_sip(link->dhcp_lease, &addresses);
-                        if (r > 0) {
-                                r = ordered_set_put_in4_addrv(&sip, addresses, r, in4_addr_is_non_local);
-                                if (r < 0)
-                                        return r;
-                        } else if (r < 0 && r != -ENODATA)
-                                return r;
-                }
-
-                if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
-                        OrderedSet **target_domains;
-                        const char *domainname;
-                        char **domains = NULL;
-
-                        target_domains = link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES ? &search_domains : &route_domains;
-                        r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
-                        if (r >= 0) {
-                                r = ordered_set_put_strdup(target_domains, domainname);
-                                if (r < 0)
-                                        return r;
-                        } else if (r != -ENODATA)
-                                return r;
-
-                        r = sd_dhcp_lease_get_search_domains(link->dhcp_lease, &domains);
-                        if (r >= 0) {
-                                r = ordered_set_put_strdupv(target_domains, domains);
-                                if (r < 0)
-                                        return r;
-                        } else if (r != -ENODATA)
-                                return r;
-                }
+                r = link_put_domains(link, /* is_route = */ true, &route_domains);
+                if (r < 0)
+                        return r;
         }
 
         if (carrier_state >= LINK_CARRIER_STATE_ENSLAVED)