diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 020dcfd56e..903ffd88de 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -2100,6 +2100,15 @@ IPv6Token=prefixstable:2002:da8:1:: + + PrefixAllowList= + + A whitespace-separated list of IPv6 prefixes. IPv6 prefixes supplied via router + advertisements in the list are allowed. Note that if PrefixAllowList= is + configured then PrefixDenyList= is ignored. + + + RouteDenyList= @@ -2108,6 +2117,15 @@ IPv6Token=prefixstable:2002:da8:1:: + + RouteAllowList= + + A whitespace-separated list of IPv6 route prefixes. IPv6 route prefixes supplied via + router advertisements in the list are allowed. Note that if RouteAllowList= is + configured then RouteDenyList= is ignored. + + + DHCPv6Client= diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index a4ac0d2023..59ab8a7843 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -69,6 +69,12 @@ void network_adjust_ipv6_accept_ra(Network *network) { if (network->ipv6_accept_ra < 0) /* 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. */ + 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); @@ -839,12 +845,17 @@ static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) { if (r < 0) return log_link_error_errno(link, r, "Failed to get route address: %m"); - if (set_contains(link->network->ndisc_deny_listed_route_prefix, &dst.in6)) { + 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); - log_link_debug(link, "Route Prefix '%s' is deny-listed, ignoring", strnull(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; } @@ -1096,12 +1107,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; } @@ -1377,7 +1393,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, @@ -1390,7 +1406,6 @@ int config_parse_ndisc_deny_listed_prefix( void *userdata) { Set **list = data; - bool is_route; int r; assert(filename); @@ -1403,8 +1418,6 @@ int config_parse_ndisc_deny_listed_prefix( return 0; } - is_route = streq_ptr(lvalue, "RouteDenyList"); - for (const char *p = rvalue;;) { _cleanup_free_ char *n = NULL; _cleanup_free_ struct in6_addr *a = NULL; @@ -1415,8 +1428,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 %sprefix, ignoring assignment: %s", - is_route ? "route " : "", rvalue); + "Failed to parse NDisc %s=, ignoring assignment: %s", + lvalue, rvalue); return 0; } if (r == 0) @@ -1425,8 +1438,8 @@ 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 %sprefix is invalid, ignoring assignment: %s", - is_route ? "route " : "", n); + "NDisc %s= entry is invalid, ignoring assignment: %s", + lvalue, n); continue; } @@ -1439,8 +1452,8 @@ int config_parse_ndisc_deny_listed_prefix( return log_oom(); if (r == 0) log_syntax(unit, LOG_WARNING, filename, line, 0, - "NDisc deny-listed %sprefix entry %s is duplicated, ignoring assignment.", - is_route ? "route " : "", n); + "NDisc %s= entry is duplicated, ignoring assignment: %s", + lvalue, n); } } diff --git a/src/network/networkd-ndisc.h b/src/network/networkd-ndisc.h index 1562411224..e2cb82b346 100644 --- a/src/network/networkd-ndisc.h +++ b/src/network/networkd-ndisc.h @@ -77,7 +77,7 @@ int ndisc_configure(Link *link); void ndisc_vacuum(Link *link); void ndisc_flush(Link *link); -CONFIG_PARSER_PROTOTYPE(config_parse_ndisc_deny_listed_prefix); +CONFIG_PARSER_PROTOTYPE(config_parse_ndisc_address_filter); CONFIG_PARSER_PROTOTYPE(config_parse_address_generation_type); CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_accept_ra_start_dhcp6_client); diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 82a4f10b04..6c999e4363 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -237,8 +237,10 @@ 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.PrefixDenyList, config_parse_ndisc_deny_listed_prefix, 0, offsetof(Network, ndisc_deny_listed_prefix) -IPv6AcceptRA.RouteDenyList, config_parse_ndisc_deny_listed_prefix, 0, offsetof(Network, ndisc_deny_listed_route_prefix) +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) +IPv6AcceptRA.RouteDenyList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_deny_listed_route_prefix) DHCPServer.MaxLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_max_lease_time_usec) DHCPServer.DefaultLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_default_lease_time_usec) DHCPServer.EmitDNS, config_parse_bool, 0, offsetof(Network, dhcp_server_emit[SD_DHCP_LEASE_DNS].emit) @@ -470,8 +472,8 @@ DHCP.RapidCommit, config_parse_bool, DHCP.ForceDHCPv6PDOtherInformation, config_parse_bool, 0, offsetof(Network, dhcp6_force_pd_other_information) DHCPv4.UseDomainName, config_parse_dhcp_use_domains, 0, offsetof(Network, dhcp_use_domains) DHCPv4.CriticalConnection, config_parse_tristate, 0, offsetof(Network, dhcp_critical) -IPv6AcceptRA.DenyList, config_parse_ndisc_deny_listed_prefix, 0, offsetof(Network, ndisc_deny_listed_prefix) -IPv6AcceptRA.BlackList, config_parse_ndisc_deny_listed_prefix, 0, offsetof(Network, ndisc_deny_listed_prefix) +IPv6AcceptRA.DenyList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_deny_listed_prefix) +IPv6AcceptRA.BlackList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_deny_listed_prefix) TrafficControlQueueingDiscipline.Parent, config_parse_qdisc_parent, _QDISC_KIND_INVALID, 0 TrafficControlQueueingDiscipline.NetworkEmulatorDelaySec, config_parse_network_emulator_delay, 0, 0 TrafficControlQueueingDiscipline.NetworkEmulatorDelayJitterSec, config_parse_network_emulator_delay, 0, 0 diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index c037904cdd..89a1f8acba 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -607,7 +607,9 @@ static Network *network_free(Network *network) { ordered_set_free(network->router_search_domains); free(network->router_dns); 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); + set_free_free(network->ndisc_allow_listed_route_prefix); free(network->bridge_name); free(network->bond_name); diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index feda19bbc1..835e7299ea 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -257,7 +257,9 @@ struct Network { IPv6AcceptRAStartDHCP6Client ipv6_accept_ra_start_dhcp6_client; uint32_t ipv6_accept_ra_route_table; Set *ndisc_deny_listed_prefix; + Set *ndisc_allow_listed_prefix; Set *ndisc_deny_listed_route_prefix; + Set *ndisc_allow_listed_route_prefix; OrderedSet *ipv6_tokens; /* LLDP support */ diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network index 66e19d865f..f1f7ad0cb8 100644 --- a/test/fuzz/fuzz-network-parser/directives.network +++ b/test/fuzz/fuzz-network-parser/directives.network @@ -310,7 +310,9 @@ UseDNS= DHCPv6Client= UseAutonomousPrefix= UseOnLinkPrefix= +PrefixAllowList= PrefixDenyList= +RouteAllowList= RouteDenyList= DenyList= BlackList=