]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/network/networkd-ndisc.c
tree-wide: use in_addr_is_set() or friends
[thirdparty/systemd.git] / src / network / networkd-ndisc.c
index 2599ec22324628263c13d3daebb65bb0899ff58c..4f71396fbb76bb50ea27f9e82a6244732ef40f5c 100644 (file)
@@ -1,10 +1,11 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 /***
   Copyright © 2014 Intel Corporation. All rights reserved.
 ***/
 
 #include <arpa/inet.h>
 #include <netinet/icmp6.h>
+#include <net/if_arp.h>
 #include <linux/if.h>
 
 #include "sd-ndisc.h"
@@ -14,7 +15,6 @@
 #include "networkd-dhcp6.h"
 #include "networkd-manager.h"
 #include "networkd-ndisc.h"
-#include "networkd-sysctl.h"
 #include "string-table.h"
 #include "string-util.h"
 #include "strv.h"
@@ -52,19 +52,32 @@ bool link_ipv6_accept_ra_enabled(Link *link) {
         if (!link_ipv6ll_enabled(link))
                 return false;
 
-        /* If unset use system default (enabled if local forwarding is disabled.
-         * disabled if local forwarding is enabled).
-         * If set, ignore or enforce RA independent of local forwarding state.
-         */
-        if (link->network->ipv6_accept_ra < 0)
+        assert(link->network->ipv6_accept_ra >= 0);
+        return link->network->ipv6_accept_ra;
+}
+
+void network_adjust_ipv6_accept_ra(Network *network) {
+        assert(network);
+
+        if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6)) {
+                if (network->ipv6_accept_ra > 0)
+                        log_warning("%s: IPv6AcceptRA= is enabled but IPv6 link local addressing is disabled or not supported. "
+                                    "Disabling IPv6AcceptRA=.", network->filename);
+                network->ipv6_accept_ra = false;
+        }
+
+        if (network->ipv6_accept_ra < 0)
                 /* default to accept RA if ip_forward is disabled and ignore RA if ip_forward is enabled */
-                return !link_ip_forward_enabled(link, AF_INET6);
-        else if (link->network->ipv6_accept_ra > 0)
-                /* accept RA even if ip_forward is enabled */
-                return true;
-        else
-                /* ignore RA */
-                return false;
+                network->ipv6_accept_ra = !FLAGS_SET(network->ip_forward, ADDRESS_FAMILY_IPV6);
+
+        /* When RouterAllowList=, PrefixAllowList= or RouteAllowList= are specified, then
+         * RouterDenyList=, PrefixDenyList= or RouteDenyList= are ignored, respectively. */
+        if (!set_isempty(network->ndisc_allow_listed_router))
+                network->ndisc_deny_listed_router = set_free_free(network->ndisc_deny_listed_router);
+        if (!set_isempty(network->ndisc_allow_listed_prefix))
+                network->ndisc_deny_listed_prefix = set_free_free(network->ndisc_deny_listed_prefix);
+        if (!set_isempty(network->ndisc_allow_listed_route_prefix))
+                network->ndisc_deny_listed_route_prefix = set_free_free(network->ndisc_deny_listed_route_prefix);
 }
 
 static int ndisc_remove_old_one(Link *link, const struct in6_addr *router, bool force);
@@ -82,7 +95,7 @@ static int ndisc_address_callback(Address *address) {
                         break;
                 }
 
-        if (IN6_IS_ADDR_UNSPECIFIED(&router)) {
+        if (in6_addr_is_null(&router)) {
                 _cleanup_free_ char *buf = NULL;
 
                 (void) in_addr_to_string(address->family, &address->in_addr, &buf);
@@ -105,6 +118,7 @@ static int ndisc_remove_old_one(Link *link, const struct in6_addr *router, bool
         NDiscDNSSL *dnssl;
         NDiscRDNSS *rdnss;
         int k, r = 0;
+        bool updated = false;
 
         assert(link);
         assert(router);
@@ -152,8 +166,6 @@ static int ndisc_remove_old_one(Link *link, const struct in6_addr *router, bool
                 log_link_debug(link, "Removing old NDisc information obtained from %s.", strna(buf));
         }
 
-        link_dirty(link);
-
         SET_FOREACH(na, link->ndisc_addresses)
                 if (na->marked && IN6_ARE_ADDR_EQUAL(&na->router, router)) {
                         k = address_remove(na->address, link, NULL);
@@ -163,18 +175,25 @@ static int ndisc_remove_old_one(Link *link, const struct in6_addr *router, bool
 
         SET_FOREACH(nr, link->ndisc_routes)
                 if (nr->marked && IN6_ARE_ADDR_EQUAL(&nr->router, router)) {
-                        k = route_remove(nr->route, link, NULL);
+                        k = route_remove(nr->route, NULL, link, NULL);
                         if (k < 0)
                                 r = k;
                 }
 
         SET_FOREACH(rdnss, link->ndisc_rdnss)
-                if (rdnss->marked && IN6_ARE_ADDR_EQUAL(&rdnss->router, router))
+                if (rdnss->marked && IN6_ARE_ADDR_EQUAL(&rdnss->router, router)) {
                         free(set_remove(link->ndisc_rdnss, rdnss));
+                        updated = true;
+                }
 
         SET_FOREACH(dnssl, link->ndisc_dnssl)
-                if (dnssl->marked && IN6_ARE_ADDR_EQUAL(&dnssl->router, router))
+                if (dnssl->marked && IN6_ARE_ADDR_EQUAL(&dnssl->router, router)) {
                         free(set_remove(link->ndisc_dnssl, dnssl));
+                        updated = true;
+                }
+
+        if (updated)
+                link_dirty(link);
 
         return r;
 }
@@ -324,6 +343,8 @@ static int ndisc_route_configure(Route *route, Link *link, sd_ndisc_router *rt)
         r = route_configure(route, link, ndisc_route_handler, &ret);
         if (r < 0)
                 return log_link_error_errno(link, r, "Failed to set NDisc route: %m");
+        if (r > 0)
+                link->ndisc_routes_configured = false;
 
         link->ndisc_routes_messages++;
 
@@ -399,12 +420,6 @@ static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
                         link_enter_failed(link);
                         return 1;
                 }
-
-                r = link_set_routes(link);
-                if (r < 0) {
-                        link_enter_failed(link);
-                        return 1;
-                }
         }
 
         return 1;
@@ -421,9 +436,11 @@ static int ndisc_address_configure(Address *address, Link *link, sd_ndisc_router
         assert(link);
         assert(rt);
 
-        r = address_configure(address, link, ndisc_address_handler, true, &ret);
+        r = address_configure(address, link, ndisc_address_handler, &ret);
         if (r < 0)
                 return log_link_error_errno(link, r, "Failed to set NDisc SLAAC address: %m");
+        if (r > 0)
+                link->ndisc_addresses_configured = false;
 
         link->ndisc_addresses_messages++;
 
@@ -461,7 +478,7 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
         union in_addr_union gateway;
         uint16_t lifetime;
         unsigned preference;
-        uint32_t mtu;
+        uint32_t table, mtu;
         usec_t time_now;
         int r;
 
@@ -479,7 +496,7 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
         if (r < 0)
                 return log_link_error_errno(link, r, "Failed to get gateway address from RA: %m");
 
-        if (address_exists(link, AF_INET6, &gateway)) {
+        if (link_has_ipv6_address(link, &gateway.in6) > 0) {
                 if (DEBUG_LOGGING) {
                         _cleanup_free_ char *buffer = NULL;
 
@@ -504,15 +521,18 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
         else if (r < 0)
                 return log_link_error_errno(link, r, "Failed to get default router MTU from RA: %m");
 
+        table = link_get_ipv6_accept_ra_route_table(link);
+
         r = route_new(&route);
         if (r < 0)
                 return log_oom();
 
         route->family = AF_INET6;
-        route->table = link_get_ipv6_accept_ra_route_table(link);
+        route->table = table;
         route->priority = link->network->dhcp6_route_metric;
         route->protocol = RTPROT_RA;
         route->pref = preference;
+        route->gw_family = AF_INET6;
         route->gw = gateway;
         route->lifetime = time_now + lifetime * USEC_PER_SEC;
         route->mtu = mtu;
@@ -523,13 +543,24 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
 
         Route *route_gw;
         HASHMAP_FOREACH(route_gw, link->network->routes_by_section) {
-                if (!route_gw->gateway_from_dhcp)
+                if (!route_gw->gateway_from_dhcp_or_ra)
                         continue;
 
-                if (route_gw->family != AF_INET6)
+                if (route_gw->gw_family != AF_INET6)
                         continue;
 
                 route_gw->gw = gateway;
+                if (!route_gw->table_set)
+                        route_gw->table = table;
+                if (!route_gw->priority_set)
+                        route_gw->priority = link->network->dhcp6_route_metric;
+                if (!route_gw->protocol_set)
+                        route_gw->protocol = RTPROT_RA;
+                if (!route_gw->pref_set)
+                        route->pref = preference;
+                route_gw->lifetime = time_now + lifetime * USEC_PER_SEC;
+                if (route_gw->mtu == 0)
+                        route_gw->mtu = mtu;
 
                 r = ndisc_route_configure(route_gw, link, rt);
                 if (r < 0)
@@ -576,7 +607,11 @@ static int make_stableprivate_address(Link *link, const struct in6_addr *prefix,
         l = MAX(DIV_ROUND_UP(prefix_len, 8), 8);
         siphash24_compress(prefix, l, &state);
         siphash24_compress_string(link->ifname, &state);
-        siphash24_compress(&link->mac, sizeof(struct ether_addr), &state);
+        /* Only last 8 bytes of IB MAC are stable */
+        if (link->iftype == ARPHRD_INFINIBAND)
+                siphash24_compress(&link->hw_addr.addr.infiniband[12], 8, &state);
+        else
+                siphash24_compress(link->hw_addr.addr.bytes, link->hw_addr.length, &state);
         siphash24_compress(&dad_counter, sizeof(uint8_t), &state);
 
         rid = htole64(siphash24_finalize(&state));
@@ -614,12 +649,11 @@ static int ndisc_router_generate_addresses(Link *link, struct in6_addr *address,
                 _cleanup_free_ struct in6_addr *new_address = NULL;
 
                 if (j->address_generation_type == IPV6_TOKEN_ADDRESS_GENERATION_PREFIXSTABLE
-                    && (IN6_IS_ADDR_UNSPECIFIED(&j->prefix) || IN6_ARE_ADDR_EQUAL(&j->prefix, address))) {
+                    && (in6_addr_is_null(&j->prefix) || IN6_ARE_ADDR_EQUAL(&j->prefix, address))) {
                         /* While this loop uses dad_counter and a retry limit as specified in RFC 7217, the loop
-                           does not actually attempt Duplicate Address Detection; the counter will be incremented
-                           only when the address generation algorithm produces an invalid address, and the loop
-                           may exit with an address which ends up being unusable due to duplication on the link.
-                        */
+                         * does not actually attempt Duplicate Address Detection; the counter will be incremented
+                         * only when the address generation algorithm produces an invalid address, and the loop
+                         * may exit with an address which ends up being unusable due to duplication on the link. */
                         for (; j->dad_counter < DAD_CONFLICTS_IDGEN_RETRIES_RFC7217; j->dad_counter++) {
                                 r = make_stableprivate_address(link, address, prefixlen, j->dad_counter, &new_address);
                                 if (r < 0)
@@ -723,8 +757,10 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
         SET_FOREACH(a, addresses) {
                 Address *existing_address;
 
+                address->in_addr.in6 = *a;
+
                 /* see RFC4862 section 5.5.3.e */
-                r = address_get(link, AF_INET6, (union in_addr_union *) a, prefixlen, &existing_address);
+                r = address_get(link, address, &existing_address);
                 if (r > 0) {
                         lifetime_remaining = existing_address->cinfo.tstamp / 100 + existing_address->cinfo.ifa_valid - time_now / USEC_PER_SEC;
                         if (lifetime_valid > NDISC_PREFIX_LFT_MIN || lifetime_valid > lifetime_remaining)
@@ -741,8 +777,6 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
                 if (address->cinfo.ifa_valid == 0)
                         continue;
 
-                address->in_addr.in6 = *a;
-
                 r = ndisc_address_configure(address, link, rt);
                 if (r < 0)
                         return log_link_error_errno(link, r, "Could not set SLAAC address: %m");
@@ -798,7 +832,7 @@ static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
 
 static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
         _cleanup_(route_freep) Route *route = NULL;
-        struct in6_addr gateway;
+        union in_addr_union gateway, dst;
         uint32_t lifetime;
         unsigned preference, prefixlen;
         usec_t time_now;
@@ -813,10 +847,39 @@ static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
         if (lifetime == 0)
                 return 0;
 
-        r = sd_ndisc_router_get_address(rt, &gateway);
+        r = sd_ndisc_router_route_get_address(rt, &dst.in6);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Failed to get route address: %m");
+
+        if ((!set_isempty(link->network->ndisc_allow_listed_route_prefix) &&
+             !set_contains(link->network->ndisc_allow_listed_route_prefix, &dst.in6)) ||
+            set_contains(link->network->ndisc_deny_listed_route_prefix, &dst.in6)) {
+                if (DEBUG_LOGGING) {
+                        _cleanup_free_ char *buf = NULL;
+
+                        (void) in_addr_to_string(AF_INET6, &dst, &buf);
+                        if (!set_isempty(link->network->ndisc_allow_listed_route_prefix))
+                                log_link_debug(link, "Route prefix '%s' is not in allow list, ignoring", strnull(buf));
+                        else
+                                log_link_debug(link, "Route prefix '%s' is in deny list, ignoring", strnull(buf));
+                }
+                return 0;
+        }
+
+        r = sd_ndisc_router_get_address(rt, &gateway.in6);
         if (r < 0)
                 return log_link_error_errno(link, r, "Failed to get gateway address from RA: %m");
 
+        if (link_has_ipv6_address(link, &gateway.in6) > 0) {
+                if (DEBUG_LOGGING) {
+                        _cleanup_free_ char *buf = NULL;
+
+                        (void) in_addr_to_string(AF_INET6, &gateway, &buf);
+                        log_link_debug(link, "Advertised route gateway, %s, is local to the link, ignoring route", strnull(buf));
+                }
+                return 0;
+        }
+
         r = sd_ndisc_router_route_get_prefixlen(rt, &prefixlen);
         if (r < 0)
                 return log_link_error_errno(link, r, "Failed to get route prefix length: %m");
@@ -838,14 +901,12 @@ static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
         route->priority = link->network->dhcp6_route_metric;
         route->protocol = RTPROT_RA;
         route->pref = preference;
-        route->gw.in6 = gateway;
+        route->gw = gateway;
+        route->gw_family = AF_INET6;
+        route->dst = dst;
         route->dst_prefixlen = prefixlen;
         route->lifetime = time_now + lifetime * USEC_PER_SEC;
 
-        r = sd_ndisc_router_route_get_address(rt, &route->dst.in6);
-        if (r < 0)
-                return log_link_error_errno(link, r, "Failed to get route address: %m");
-
         r = ndisc_route_configure(route, link, rt);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not set additional route: %m");
@@ -874,6 +935,7 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
         struct in6_addr router;
         NDiscRDNSS *rdnss;
         usec_t time_now;
+        bool updated = false;
         int n, r;
 
         assert(link);
@@ -935,8 +997,13 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
                 if (r < 0)
                         return log_oom();
                 assert(r > 0);
+
+                updated = true;
         }
 
+        if (updated)
+                link_dirty(link);
+
         return 0;
 }
 
@@ -961,6 +1028,7 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
         uint32_t lifetime;
         usec_t time_now;
         NDiscDNSSL *dnssl;
+        bool updated = false;
         char **j;
         int r;
 
@@ -1020,8 +1088,13 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
                 if (r < 0)
                         return log_oom();
                 assert(r > 0);
+
+                updated = true;
         }
 
+        if (updated)
+                link_dirty(link);
+
         return 0;
 }
 
@@ -1052,12 +1125,17 @@ static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
                         if (r < 0)
                                 return log_link_error_errno(link, r, "Failed to get prefix address: %m");
 
-                        if (set_contains(link->network->ndisc_deny_listed_prefix, &a.in6)) {
+                        if ((!set_isempty(link->network->ndisc_allow_listed_prefix) &&
+                             !set_contains(link->network->ndisc_allow_listed_prefix, &a.in6)) ||
+                            set_contains(link->network->ndisc_deny_listed_prefix, &a.in6)) {
                                 if (DEBUG_LOGGING) {
                                         _cleanup_free_ char *b = NULL;
 
                                         (void) in_addr_to_string(AF_INET6, &a, &b);
-                                        log_link_debug(link, "Prefix '%s' is deny-listed, ignoring", strna(b));
+                                        if (!set_isempty(link->network->ndisc_allow_listed_prefix))
+                                                log_link_debug(link, "Prefix '%s' is not in allow list, ignoring", strna(b));
+                                        else
+                                                log_link_debug(link, "Prefix '%s' is in deny list, ignoring", strna(b));
                                 }
                                 break;
                         }
@@ -1108,7 +1186,7 @@ static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
 }
 
 static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
-        struct in6_addr router;
+        union in_addr_union router;
         uint64_t flags;
         NDiscAddress *na;
         NDiscRoute *nr;
@@ -1119,34 +1197,48 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
         assert(link->manager);
         assert(rt);
 
-        link->ndisc_addresses_configured = false;
-        link->ndisc_routes_configured = false;
-
-        link_dirty(link);
-
-        r = sd_ndisc_router_get_address(rt, &router);
+        r = sd_ndisc_router_get_address(rt, &router.in6);
         if (r < 0)
                 return log_link_error_errno(link, r, "Failed to get router address from RA: %m");
 
+        if ((!set_isempty(link->network->ndisc_allow_listed_router) &&
+             !set_contains(link->network->ndisc_allow_listed_router, &router.in6)) ||
+            set_contains(link->network->ndisc_deny_listed_router, &router.in6)) {
+                if (DEBUG_LOGGING) {
+                        _cleanup_free_ char *buf = NULL;
+
+                        (void) in_addr_to_string(AF_INET6, &router, &buf);
+                        if (!set_isempty(link->network->ndisc_allow_listed_router))
+                                log_link_debug(link, "Router '%s' is not in allow list, ignoring", strna(buf));
+                        else
+                                log_link_debug(link, "Router '%s' is in deny list, ignoring", strna(buf));
+                }
+                return 0;
+        }
+
         SET_FOREACH(na, link->ndisc_addresses)
-                if (IN6_ARE_ADDR_EQUAL(&na->router, &router))
+                if (IN6_ARE_ADDR_EQUAL(&na->router, &router.in6))
                         na->marked = true;
 
         SET_FOREACH(nr, link->ndisc_routes)
-                if (IN6_ARE_ADDR_EQUAL(&nr->router, &router))
+                if (IN6_ARE_ADDR_EQUAL(&nr->router, &router.in6))
                         nr->marked = true;
 
         r = sd_ndisc_router_get_flags(rt, &flags);
         if (r < 0)
                 return log_link_error_errno(link, r, "Failed to get RA flags: %m");
 
-        if ((flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER) && link->network->ipv6_accept_ra_start_dhcp6_client)) {
+        if ((flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER) &&
+             link->network->ipv6_accept_ra_start_dhcp6_client != IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO) ||
+            link->network->ipv6_accept_ra_start_dhcp6_client == IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS) {
 
-                if (link->network->ipv6_accept_ra_start_dhcp6_client == IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS)
-                        r = dhcp6_request_address(link, false);
-                else
+                if (flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER))
                         /* (re)start DHCPv6 client in stateful or stateless mode according to RA flags */
                         r = dhcp6_request_address(link, !(flags & ND_RA_FLAG_MANAGED));
+                else
+                        /* When IPv6AcceptRA.DHCPv6Client=always, start dhcp6 client in managed mode
+                         * even if router does not have M or O flag. */
+                        r = dhcp6_request_address(link, false);
                 if (r < 0 && r != -EBUSY)
                         return log_link_error_errno(link, r, "Could not acquire DHCPv6 lease on NDisc request: %m");
                 else
@@ -1162,16 +1254,9 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
 
         if (link->ndisc_addresses_messages == 0)
                 link->ndisc_addresses_configured = true;
-        else {
+        else
                 log_link_debug(link, "Setting SLAAC addresses.");
 
-                /* address_handler calls link_set_routes() and link_set_nexthop(). Before they are
-                 * called, the related flags must be cleared. Otherwise, the link becomes configured
-                 * state before routes are configured. */
-                link->static_routes_configured = false;
-                link->static_nexthops_configured = false;
-        }
-
         if (link->ndisc_routes_messages == 0)
                 link->ndisc_routes_configured = true;
         else
@@ -1239,7 +1324,7 @@ int ndisc_configure(Link *link) {
                         return r;
         }
 
-        r = sd_ndisc_set_mac(link->ndisc, &link->mac);
+        r = sd_ndisc_set_mac(link->ndisc, &link->hw_addr.addr.ether);
         if (r < 0)
                 return r;
 
@@ -1258,7 +1343,6 @@ void ndisc_vacuum(Link *link) {
         NDiscRDNSS *r;
         NDiscDNSSL *d;
         usec_t time_now;
-        bool updated = false;
 
         assert(link);
 
@@ -1267,19 +1351,12 @@ void ndisc_vacuum(Link *link) {
         time_now = now(clock_boottime_or_monotonic());
 
         SET_FOREACH(r, link->ndisc_rdnss)
-                if (r->valid_until < time_now) {
+                if (r->valid_until < time_now)
                         free(set_remove(link->ndisc_rdnss, r));
-                        updated = true;
-                }
 
         SET_FOREACH(d, link->ndisc_dnssl)
-                if (d->valid_until < time_now) {
+                if (d->valid_until < time_now)
                         free(set_remove(link->ndisc_dnssl, d));
-                        updated = true;
-                }
-
-        if (updated)
-                link_dirty(link);
 }
 
 void ndisc_flush(Link *link) {
@@ -1329,7 +1406,7 @@ DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
                 ipv6_token_compare_func,
                 free);
 
-int config_parse_ndisc_deny_listed_prefix(
+int config_parse_ndisc_address_filter(
                 const char *unit,
                 const char *filename,
                 unsigned line,
@@ -1341,8 +1418,7 @@ int config_parse_ndisc_deny_listed_prefix(
                 void *data,
                 void *userdata) {
 
-        Network *network = data;
-        const char *p;
+        Set **list = data;
         int r;
 
         assert(filename);
@@ -1351,11 +1427,11 @@ int config_parse_ndisc_deny_listed_prefix(
         assert(data);
 
         if (isempty(rvalue)) {
-                network->ndisc_deny_listed_prefix = set_free_free(network->ndisc_deny_listed_prefix);
+                *list = set_free_free(*list);
                 return 0;
         }
 
-        for (p = rvalue;;) {
+        for (const char *p = rvalue;;) {
                 _cleanup_free_ char *n = NULL;
                 _cleanup_free_ struct in6_addr *a = NULL;
                 union in_addr_union ip;
@@ -1365,8 +1441,8 @@ int config_parse_ndisc_deny_listed_prefix(
                         return log_oom();
                 if (r < 0) {
                         log_syntax(unit, LOG_WARNING, filename, line, r,
-                                   "Failed to parse NDisc deny-listed prefix, ignoring assignment: %s",
-                                   rvalue);
+                                   "Failed to parse NDisc %s=, ignoring assignment: %s",
+                                   lvalue, rvalue);
                         return 0;
                 }
                 if (r == 0)
@@ -1375,20 +1451,22 @@ int config_parse_ndisc_deny_listed_prefix(
                 r = in_addr_from_string(AF_INET6, n, &ip);
                 if (r < 0) {
                         log_syntax(unit, LOG_WARNING, filename, line, r,
-                                   "NDisc deny-listed prefix is invalid, ignoring assignment: %s", n);
+                                   "NDisc %s= entry is invalid, ignoring assignment: %s",
+                                   lvalue, n);
                         continue;
                 }
 
-                if (set_contains(network->ndisc_deny_listed_prefix, &ip.in6))
-                        continue;
-
                 a = newdup(struct in6_addr, &ip.in6, 1);
                 if (!a)
                         return log_oom();
 
-                r = set_ensure_consume(&network->ndisc_deny_listed_prefix, &in6_addr_hash_ops, TAKE_PTR(a));
+                r = set_ensure_consume(list, &in6_addr_hash_ops, TAKE_PTR(a));
                 if (r < 0)
                         return log_oom();
+                if (r == 0)
+                        log_syntax(unit, LOG_WARNING, filename, line, 0,
+                                   "NDisc %s= entry is duplicated, ignoring assignment: %s",
+                                   lvalue, n);
         }
 }
 
@@ -1461,11 +1539,9 @@ int config_parse_address_generation_type(
                 token->prefix = buffer.in6;
         }
 
-        r = ordered_set_ensure_allocated(&network->ipv6_tokens, &ipv6_token_hash_ops);
-        if (r < 0)
+        r = ordered_set_ensure_put(&network->ipv6_tokens, &ipv6_token_hash_ops, token);
+        if (r == -ENOMEM)
                 return log_oom();
-
-        r = ordered_set_put(network->ipv6_tokens, token);
         if (r == -EEXIST)
                 log_syntax(unit, LOG_DEBUG, filename, line, r,
                            "IPv6 token '%s' is duplicated, ignoring: %m", rvalue);