1
0
mirror of https://github.com/systemd/systemd synced 2024-07-01 07:34:28 +00:00

network/ndisc: drop configurations when received RA with zero lifetime

This commit is contained in:
Yu Watanabe 2024-02-19 10:35:48 +09:00
parent 828b5dbf2f
commit 479d3e1994

View File

@ -273,6 +273,39 @@ static int ndisc_request_route(Route *route, Link *link, sd_ndisc_router *rt) {
return 0;
}
static int ndisc_remove_route(Route *route, Link *link) {
int r;
assert(route);
assert(link);
assert(link->manager);
ndisc_set_route_priority(link, route);
if (!route->table_set)
route->table = link_get_ipv6_accept_ra_route_table(link);
r = route_adjust_nexthops(route, link);
if (r < 0)
return r;
if (route->pref_set) {
ndisc_set_route_priority(link, route);
return route_remove_and_cancel(route, link->manager);
}
uint8_t pref;
FOREACH_ARGUMENT(pref, SD_NDISC_PREFERENCE_LOW, SD_NDISC_PREFERENCE_MEDIUM, SD_NDISC_PREFERENCE_HIGH) {
route->pref = pref;
ndisc_set_route_priority(link, route);
r = route_remove_and_cancel(route, link->manager);
if (r < 0)
return r;
}
return 0;
}
static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Address *address) {
int r;
@ -340,6 +373,55 @@ static int ndisc_request_address(Address *address, Link *link, sd_ndisc_router *
return 0;
}
static int ndisc_router_drop_default(Link *link, sd_ndisc_router *rt) {
_cleanup_(route_unrefp) Route *route = NULL;
struct in6_addr gateway;
int r;
assert(link);
assert(link->network);
assert(rt);
r = sd_ndisc_router_get_address(rt, &gateway);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to get router address from RA: %m");
r = route_new(&route);
if (r < 0)
return log_oom();
route->family = AF_INET6;
route->nexthop.family = AF_INET6;
route->nexthop.gw.in6 = gateway;
r = ndisc_remove_route(route, link);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to remove the default gateway configured by RA: %m");
Route *route_gw;
HASHMAP_FOREACH(route_gw, link->network->routes_by_section) {
_cleanup_(route_unrefp) Route *tmp = NULL;
if (!route_gw->gateway_from_dhcp_or_ra)
continue;
if (route_gw->nexthop.family != AF_INET6)
continue;
r = route_dup(route_gw, NULL, &tmp);
if (r < 0)
return r;
tmp->nexthop.gw.in6 = gateway;
r = ndisc_remove_route(tmp, link);
if (r < 0)
return log_link_warning_errno(link, r, "Could not remove semi-static gateway: %m");
}
return 0;
}
static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
usec_t lifetime_usec;
struct in6_addr gateway;
@ -350,6 +432,13 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
assert(link->network);
assert(rt);
/* If the router lifetime is zero, the router should not be used as the default gateway. */
r = sd_ndisc_router_get_lifetime(rt, NULL);
if (r < 0)
return r;
if (r == 0)
return ndisc_router_drop_default(link, rt);
if (!link->network->ipv6_accept_ra_use_gateway &&
hashmap_isempty(link->network->routes_by_section))
return 0;
@ -578,9 +667,22 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
address->lifetime_valid_usec = lifetime_valid_usec;
address->lifetime_preferred_usec = lifetime_preferred_usec;
r = ndisc_request_address(address, link, rt);
if (r < 0)
return log_link_warning_errno(link, r, "Could not request SLAAC address: %m");
/* draft-ietf-6man-slaac-renum-07 section 4.2
* https://datatracker.ietf.org/doc/html/draft-ietf-6man-slaac-renum-07#section-4.2
*
* If the advertised prefix is equal to the prefix of an address configured by stateless
* autoconfiguration in the list, the valid lifetime and the preferred lifetime of the
* address should be updated by processing the Valid Lifetime and the Preferred Lifetime
* (respectively) in the received advertisement. */
if (lifetime_valid_usec == 0) {
r = address_remove_and_cancel(address, link);
if (r < 0)
return log_link_warning_errno(link, r, "Could not remove SLAAC address: %m");
} else {
r = ndisc_request_address(address, link, rt);
if (r < 0)
return log_link_warning_errno(link, r, "Could not request SLAAC address: %m");
}
}
return 0;
@ -636,7 +738,7 @@ static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
static int ndisc_router_drop_onlink_prefix(Link *link, sd_ndisc_router *rt) {
_cleanup_(route_unrefp) Route *route = NULL;
unsigned prefixlen, preference;
unsigned prefixlen;
struct in6_addr prefix;
usec_t lifetime_usec;
int r;
@ -669,11 +771,6 @@ static int ndisc_router_drop_onlink_prefix(Link *link, sd_ndisc_router *rt) {
if (r < 0)
return log_link_warning_errno(link, r, "Failed to get prefix length: %m");
/* Prefix Information option does not have preference, hence we use the 'main' preference here */
r = sd_ndisc_router_get_preference(rt, &preference);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to get router preference from RA: %m");
r = route_new(&route);
if (r < 0)
return log_oom();
@ -681,16 +778,8 @@ static int ndisc_router_drop_onlink_prefix(Link *link, sd_ndisc_router *rt) {
route->family = AF_INET6;
route->dst.in6 = prefix;
route->dst_prefixlen = prefixlen;
route->table = link_get_ipv6_accept_ra_route_table(link);
route->pref = preference;
ndisc_set_route_priority(link, route);
route->protocol = RTPROT_RA;
r = route_adjust_nexthops(route, link);
if (r < 0)
return r;
r = route_remove_and_cancel(route, link->manager);
r = ndisc_remove_route(route, link);
if (r < 0)
return log_link_warning_errno(link, r, "Could not remove prefix route: %m");
@ -715,7 +804,7 @@ static int ndisc_router_process_prefix(Link *link, sd_ndisc_router *rt) {
* A router SHOULD NOT send a prefix option for the link-local prefix and a host SHOULD ignore such
* a prefix option. */
if (in6_addr_is_link_local(&a)) {
log_link_debug(link, "Received link-local prefix, ignoring autonomous prefix.");
log_link_debug(link, "Received link-local prefix, ignoring prefix.");
return 0;
}