1
0
mirror of https://github.com/systemd/systemd.git synced 2024-12-23 21:35:11 +03:00

network: fix logic for checking gateway address is ready

This fixes the followings:
- The corresponding route or address to the gateway address must be in
  the same link.
- IPv6 link local address is not necessary to be reachable.

Fixes an issue reported in https://github.com/systemd/systemd/issues/8686#issuecomment-902562324.
This commit is contained in:
Yu Watanabe 2021-08-21 03:51:39 +09:00
parent 66dc9b4634
commit 3333350a0e
3 changed files with 43 additions and 36 deletions

View File

@ -793,12 +793,7 @@ static bool nexthop_is_ready_to_configure(Link *link, const NextHop *nexthop) {
}
}
if (nexthop->onlink <= 0 &&
in_addr_is_set(nexthop->family, &nexthop->gw) &&
!manager_address_is_reachable(link->manager, nexthop->family, &nexthop->gw))
return false;
return true;
return gateway_is_ready(link, nexthop->onlink, nexthop->family, &nexthop->gw);
}
int request_process_nexthop(Request *req) {

View File

@ -750,6 +750,8 @@ static bool prefix_route_address_is_reachable(const Address *a, int family, cons
if (a->family != family)
return false;
if (!address_is_ready(a))
return false;
if (FLAGS_SET(a->flags, IFA_F_NOPREFIXROUTE))
return false;
if (in_addr_is_set(a->family, &a->in_addr_peer))
@ -763,37 +765,34 @@ static bool prefix_route_address_is_reachable(const Address *a, int family, cons
FAMILY_ADDRESS_SIZE(family) * 8) > 0;
}
bool manager_address_is_reachable(Manager *manager, int family, const union in_addr_union *address) {
Link *link;
static bool link_address_is_reachable(Link *link, int family, const union in_addr_union *address) {
Route *route;
assert(manager);
assert(link);
assert(link->manager);
assert(IN_SET(family, AF_INET, AF_INET6));
assert(address);
HASHMAP_FOREACH(link, manager->links_by_index) {
Route *route;
SET_FOREACH(route, link->routes)
if (route_address_is_reachable(route, family, address))
return true;
SET_FOREACH(route, link->routes_foreign)
if (route_address_is_reachable(route, family, address))
return true;
}
SET_FOREACH(route, link->routes)
if (route_address_is_reachable(route, family, address))
return true;
SET_FOREACH(route, link->routes_foreign)
if (route_address_is_reachable(route, family, address))
return true;
/* If we do not manage foreign routes, then there may exist a prefix route we do not know,
* which was created on configuring an address. Hence, also check the addresses. */
if (!manager->manage_foreign_routes)
HASHMAP_FOREACH(link, manager->links_by_index) {
Address *a;
if (!link->manager->manage_foreign_routes) {
Address *a;
SET_FOREACH(a, link->addresses)
if (prefix_route_address_is_reachable(a, family, address))
return true;
SET_FOREACH(a, link->addresses_foreign)
if (prefix_route_address_is_reachable(a, family, address))
return true;
}
SET_FOREACH(a, link->addresses)
if (prefix_route_address_is_reachable(a, family, address))
return true;
SET_FOREACH(a, link->addresses_foreign)
if (prefix_route_address_is_reachable(a, family, address))
return true;
}
return false;
}
@ -1689,6 +1688,22 @@ int link_request_static_routes(Link *link, bool only_ipv4) {
return 0;
}
bool gateway_is_ready(Link *link, int onlink, int family, const union in_addr_union *gw) {
assert(link);
assert(gw);
if (onlink > 0)
return true;
if (!in_addr_is_set(family, gw))
return true;
if (family == AF_INET6 && in6_addr_is_link_local(&gw->in6))
return true;
return link_address_is_reachable(link, family, gw);
}
static int route_is_ready_to_configure(const Route *route, Link *link) {
MultipathRoute *m;
NextHop *nh = NULL;
@ -1732,19 +1747,13 @@ static int route_is_ready_to_configure(const Route *route, Link *link) {
return r;
}
if (route->gateway_onlink <= 0 &&
in_addr_is_set(route->gw_family, &route->gw) > 0 &&
!manager_address_is_reachable(link->manager, route->gw_family, &route->gw))
if (!gateway_is_ready(link, route->gateway_onlink, route->gw_family, &route->gw))
return false;
ORDERED_SET_FOREACH(m, route->multipath_routes) {
union in_addr_union a = m->gateway.address;
Link *l = NULL;
if (route->gateway_onlink <= 0 &&
!manager_address_is_reachable(link->manager, m->gateway.family, &a))
return false;
if (m->ifname) {
if (link_get_by_name(link->manager, m->ifname, &l) < 0)
return false;
@ -1756,6 +1765,9 @@ static int route_is_ready_to_configure(const Route *route, Link *link) {
}
if (l && !link_is_ready_to_configure(l, true))
return false;
if (!gateway_is_ready(l ?: link, route->gateway_onlink, m->gateway.family, &a))
return false;
}
return true;

View File

@ -78,8 +78,8 @@ int route_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Li
int route_remove(const Route *route, Manager *manager, Link *link);
int link_has_route(Link *link, const Route *route);
bool manager_address_is_reachable(Manager *manager, int family, const union in_addr_union *address);
int manager_find_uplink(Manager *m, int family, Link *exclude, Link **ret);
bool gateway_is_ready(Link *link, int onlink, int family, const union in_addr_union *gw);
int link_drop_routes(Link *link);
int link_drop_foreign_routes(Link *link);