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 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);
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);
NDiscDNSSL *dnssl;
NDiscRDNSS *rdnss;
int k, r = 0;
+ bool updated = false;
assert(link);
assert(router);
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);
}
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;
}
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++;
link_enter_failed(link);
return 1;
}
-
- r = link_set_routes(link);
- if (r < 0) {
- link_enter_failed(link);
- return 1;
- }
}
return 1;
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++;
_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)
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;
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");
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");
struct in6_addr router;
NDiscRDNSS *rdnss;
usec_t time_now;
+ bool updated = false;
int n, r;
assert(link);
if (r < 0)
return log_oom();
assert(r > 0);
+
+ updated = true;
}
+ if (updated)
+ link_dirty(link);
+
return 0;
}
uint32_t lifetime;
usec_t time_now;
NDiscDNSSL *dnssl;
+ bool updated = false;
char **j;
int r;
if (r < 0)
return log_oom();
assert(r > 0);
+
+ updated = true;
}
+ if (updated)
+ link_dirty(link);
+
return 0;
}
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;
}
}
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;
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 (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
NDiscRDNSS *r;
NDiscDNSSL *d;
usec_t time_now;
- bool updated = false;
assert(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) {
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,
void *data,
void *userdata) {
- Network *network = data;
- const char *p;
+ Set **list = data;
int r;
assert(filename);
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;
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)
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);
}
}
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);