diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index 903ffd88de..7baf1a9df0 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -2092,6 +2092,23 @@ IPv6Token=prefixstable:2002:da8:1::
+
+ RouterDenyList=
+
+ A whitespace-separated list of IPv6 router addresses. Any information advertised by
+ the listed router is ignored.
+
+
+
+
+ RouterAllowList=
+
+ A whitespace-separated list of IPv6 router addresses. Only information advertised by
+ the listed router is accepted. Note that if RouterAllowList= is
+ configured then RouterDenyList= is ignored.
+
+
+
PrefixDenyList=
diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c
index 59ab8a7843..3f1837f591 100644
--- a/src/network/networkd-ndisc.c
+++ b/src/network/networkd-ndisc.c
@@ -70,7 +70,10 @@ void network_adjust_ipv6_accept_ra(Network *network) {
/* default to accept RA if ip_forward is disabled and ignore RA if ip_forward is enabled */
network->ipv6_accept_ra = !FLAGS_SET(network->ip_forward, ADDRESS_FAMILY_IPV6);
- /* When PrefixAllowList= or RouteAllowList= are specified, then PrefixDenyList= or RouteDenyList= are ignored. */
+ /* 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))
@@ -1168,7 +1171,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;
@@ -1179,21 +1182,36 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
assert(link->manager);
assert(rt);
+ 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;
+ }
+
link->ndisc_addresses_configured = false;
link->ndisc_routes_configured = false;
link_dirty(link);
- r = sd_ndisc_router_get_address(rt, &router);
- if (r < 0)
- return log_link_error_errno(link, r, "Failed to get router address from RA: %m");
-
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);
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 6c999e4363..2a6cb6deae 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -237,6 +237,8 @@ IPv6AcceptRA.UseDNS, config_parse_bool,
IPv6AcceptRA.UseDomains, config_parse_dhcp_use_domains, 0, offsetof(Network, ipv6_accept_ra_use_domains)
IPv6AcceptRA.DHCPv6Client, config_parse_ipv6_accept_ra_start_dhcp6_client, 0, offsetof(Network, ipv6_accept_ra_start_dhcp6_client)
IPv6AcceptRA.RouteTable, config_parse_section_route_table, 0, 0
+IPv6AcceptRA.RouterAllowList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_allow_listed_router)
+IPv6AcceptRA.RouterDenyList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_deny_listed_router)
IPv6AcceptRA.PrefixAllowList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_allow_listed_prefix)
IPv6AcceptRA.PrefixDenyList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_deny_listed_prefix)
IPv6AcceptRA.RouteAllowList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_allow_listed_route_prefix)
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 89a1f8acba..daece28dbb 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -606,6 +606,8 @@ static Network *network_free(Network *network) {
ordered_set_free(network->router_search_domains);
free(network->router_dns);
+ set_free_free(network->ndisc_deny_listed_router);
+ set_free_free(network->ndisc_allow_listed_router);
set_free_free(network->ndisc_deny_listed_prefix);
set_free_free(network->ndisc_allow_listed_prefix);
set_free_free(network->ndisc_deny_listed_route_prefix);
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index 835e7299ea..32f5ae8d72 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -256,6 +256,8 @@ struct Network {
DHCPUseDomains ipv6_accept_ra_use_domains;
IPv6AcceptRAStartDHCP6Client ipv6_accept_ra_start_dhcp6_client;
uint32_t ipv6_accept_ra_route_table;
+ Set *ndisc_deny_listed_router;
+ Set *ndisc_allow_listed_router;
Set *ndisc_deny_listed_prefix;
Set *ndisc_allow_listed_prefix;
Set *ndisc_deny_listed_route_prefix;
diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network
index f1f7ad0cb8..f57f0cd561 100644
--- a/test/fuzz/fuzz-network-parser/directives.network
+++ b/test/fuzz/fuzz-network-parser/directives.network
@@ -310,6 +310,8 @@ UseDNS=
DHCPv6Client=
UseAutonomousPrefix=
UseOnLinkPrefix=
+RouterAllowList=
+RouterDenyList=
PrefixAllowList=
PrefixDenyList=
RouteAllowList=