1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2024-12-22 13:33:56 +03:00

network: dhcp4: ignore gateway in static routes if destination is link-local or in the same network

This also configures routes to gateways in static routes if the
destination is not in the same network.
This commit is contained in:
Yu Watanabe 2021-04-12 23:52:49 +09:00
parent b714d9a6e3
commit 7f206276ad

View File

@ -143,19 +143,6 @@ static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *li
return 1;
}
static int route_scope_from_address(const Route *route, const struct in_addr *self_addr) {
assert(route);
assert(self_addr);
if (in4_addr_is_localhost(&route->dst.in) ||
(in4_addr_is_set(self_addr) && in4_addr_equal(&route->dst.in, self_addr)))
return RT_SCOPE_HOST;
else if (in4_addr_is_null(&route->gw.in))
return RT_SCOPE_LINK;
else
return RT_SCOPE_UNIVERSE;
}
static int dhcp_route_configure(Route *route, Link *link) {
Route *ret;
int r;
@ -250,11 +237,95 @@ static int link_set_dhcp_route_to_gateway(Link *link, const struct in_addr *gw)
return dhcp_route_configure(route, link);
}
static int dhcp_route_configure_auto(
Route *route,
Link *link,
const struct in_addr *gw) {
struct in_addr address, netmask, prefix;
uint8_t prefixlen;
int r;
assert(route);
assert(link);
assert(link->dhcp_lease);
assert(gw);
/* The route object may be reused in an iteration. All elements must be set or cleared. */
r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
if (r < 0)
return r;
r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
if (r < 0)
return r;
prefix.s_addr = address.s_addr & netmask.s_addr;
prefixlen = in4_addr_netmask_to_prefixlen(&netmask);
if (in4_addr_is_localhost(&route->dst.in)) {
if (in4_addr_is_set(gw))
log_link_debug(link, "DHCP: requested route destination "IPV4_ADDRESS_FMT_STR"/%u is localhost, "
"ignoring gateway address "IPV4_ADDRESS_FMT_STR,
IPV4_ADDRESS_FMT_VAL(route->dst.in), route->dst_prefixlen, IPV4_ADDRESS_FMT_VAL(*gw));
route->scope = RT_SCOPE_HOST;
route->gw_family = AF_UNSPEC;
route->gw = IN_ADDR_NULL;
route->prefsrc = IN_ADDR_NULL;
} else if (in4_addr_equal(&route->dst.in, &address)) {
if (in4_addr_is_set(gw))
log_link_debug(link, "DHCP: requested route destination "IPV4_ADDRESS_FMT_STR"/%u is equivalent to the acquired address, "
"ignoring gateway address "IPV4_ADDRESS_FMT_STR,
IPV4_ADDRESS_FMT_VAL(route->dst.in), route->dst_prefixlen, IPV4_ADDRESS_FMT_VAL(*gw));
route->scope = RT_SCOPE_HOST;
route->gw_family = AF_UNSPEC;
route->gw = IN_ADDR_NULL;
route->prefsrc.in = address;
} else if (route->dst_prefixlen >= prefixlen &&
(route->dst.in.s_addr & netmask.s_addr) == prefix.s_addr) {
if (in4_addr_is_set(gw))
log_link_debug(link, "DHCP: requested route destination "IPV4_ADDRESS_FMT_STR"/%u is in the assigned network "
IPV4_ADDRESS_FMT_STR"/%u, ignoring gateway address "IPV4_ADDRESS_FMT_STR,
IPV4_ADDRESS_FMT_VAL(route->dst.in), route->dst_prefixlen,
IPV4_ADDRESS_FMT_VAL(prefix), prefixlen,
IPV4_ADDRESS_FMT_VAL(*gw));
route->scope = RT_SCOPE_LINK;
route->gw_family = AF_UNSPEC;
route->gw = IN_ADDR_NULL;
route->prefsrc.in = address;
} else {
if (in4_addr_is_null(gw)) {
log_link_debug(link, "DHCP: requested route destination "IPV4_ADDRESS_FMT_STR"/%u is not in the assigned network "
IPV4_ADDRESS_FMT_STR"/%u, but no gateway is specified, ignoring.",
IPV4_ADDRESS_FMT_VAL(route->dst.in), route->dst_prefixlen,
IPV4_ADDRESS_FMT_VAL(prefix), prefixlen);
return 0;
}
r = link_set_dhcp_route_to_gateway(link, gw);
if (r < 0)
return r;
route->scope = RT_SCOPE_UNIVERSE;
route->gw_family = AF_INET;
route->gw.in = *gw;
route->prefsrc.in = address;
}
return dhcp_route_configure(route, link);
}
static int link_set_dhcp_static_routes(Link *link) {
_cleanup_free_ sd_dhcp_route **static_routes = NULL;
bool classless_route = false, static_route = false;
_cleanup_(route_freep) Route *route = NULL;
struct in_addr address;
int n, r;
assert(link);
@ -263,10 +334,6 @@ static int link_set_dhcp_static_routes(Link *link) {
if (!link->network->dhcp_use_routes)
return 0;
r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
if (r < 0)
return r;
n = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes);
if (IN_SET(n, 0, -ENODATA)) {
log_link_debug(link, "DHCP: No static routes received from DHCP server.");
@ -303,11 +370,13 @@ static int link_set_dhcp_static_routes(Link *link) {
route->mtu = link->network->dhcp_route_mtu;
for (int i = 0; i < n; i++) {
struct in_addr gw;
if (sd_dhcp_route_get_option(static_routes[i]) !=
(classless_route ? SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE : SD_DHCP_OPTION_STATIC_ROUTE))
continue;
r = sd_dhcp_route_get_gateway(static_routes[i], &route->gw.in);
r = sd_dhcp_route_get_gateway(static_routes[i], &gw);
if (r < 0)
return r;
@ -319,13 +388,7 @@ static int link_set_dhcp_static_routes(Link *link) {
if (r < 0)
return r;
route->scope = route_scope_from_address(route, &address);
if (IN_SET(route->scope, RT_SCOPE_LINK, RT_SCOPE_UNIVERSE))
route->prefsrc.in = address;
else
route->prefsrc = IN_ADDR_NULL;
r = dhcp_route_configure(route, link);
r = dhcp_route_configure_auto(route, link, &gw);
if (r < 0)
return r;
}