1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-01-25 06:03:40 +03:00

network: fixes gateway assignment through DHCPv4

This fixes the following issue:
- If a DHCP lease does not contains router option, then routes with
`Gateway=_dhcp` setting introduce unexpected results.

This also makes several failure paths critical. And adjust warnings when
classless routes are provided.
This commit is contained in:
Yu Watanabe 2020-08-26 22:31:01 +09:00 committed by Lennart Poettering
parent 5b49641015
commit 2200c3cf56

View File

@ -251,11 +251,10 @@ static int dhcp_prefix_route_from_lease(
static int link_set_dhcp_routes(Link *link) { static int link_set_dhcp_routes(Link *link) {
_cleanup_free_ sd_dhcp_route **static_routes = NULL; _cleanup_free_ sd_dhcp_route **static_routes = NULL;
bool classless_route = false, static_route = false; bool classless_route = false, static_route = false;
const struct in_addr *router;
struct in_addr address; struct in_addr address;
int r, n, i;
uint32_t table; uint32_t table;
Route *rt; Route *rt;
int r, n;
assert(link); assert(link);
@ -298,9 +297,9 @@ static int link_set_dhcp_routes(Link *link) {
if (n == -ENODATA) if (n == -ENODATA)
log_link_debug_errno(link, n, "DHCP: No routes received from DHCP server: %m"); log_link_debug_errno(link, n, "DHCP: No routes received from DHCP server: %m");
else if (n < 0) else if (n < 0)
log_link_debug_errno(link, n, "DHCP: could not get routes: %m"); return log_link_error_errno(link, n, "DHCP: could not get routes: %m");
for (i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
switch (sd_dhcp_route_get_option(static_routes[i])) { switch (sd_dhcp_route_get_option(static_routes[i])) {
case SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE: case SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
classless_route = true; classless_route = true;
@ -312,11 +311,14 @@ static int link_set_dhcp_routes(Link *link) {
} }
if (link->network->dhcp_use_routes) { if (link->network->dhcp_use_routes) {
for (i = 0; i < n; i++) { /* if the DHCP server returns both a Classless Static Routes option and a Static Routes option,
* the DHCP client MUST ignore the Static Routes option. */
if (classless_route && static_route)
log_link_warning(link, "Classless static routes received from DHCP server: ignoring static-route option");
for (int i = 0; i < n; i++) {
_cleanup_(route_freep) Route *route = NULL; _cleanup_(route_freep) Route *route = NULL;
/* if the DHCP server returns both a Classless Static Routes option and a Static Routes option,
the DHCP client MUST ignore the Static Routes option. */
if (classless_route && if (classless_route &&
sd_dhcp_route_get_option(static_routes[i]) != SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE) sd_dhcp_route_get_option(static_routes[i]) != SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE)
continue; continue;
@ -347,20 +349,20 @@ static int link_set_dhcp_routes(Link *link) {
} }
if (link->network->dhcp_use_gateway) { if (link->network->dhcp_use_gateway) {
const struct in_addr *router;
r = sd_dhcp_lease_get_router(link->dhcp_lease, &router); r = sd_dhcp_lease_get_router(link->dhcp_lease, &router);
if (IN_SET(r, 0, -ENODATA)) if (IN_SET(r, 0, -ENODATA))
log_link_info(link, "DHCP: No gateway received from DHCP server."); log_link_info(link, "DHCP: No gateway received from DHCP server.");
else if (r < 0) else if (r < 0)
log_link_warning_errno(link, r, "DHCP error: could not get gateway: %m"); return log_link_error_errno(link, r, "DHCP error: could not get gateway: %m");
else if (in4_addr_is_null(&router[0])) else if (in4_addr_is_null(&router[0]))
log_link_info(link, "DHCP: Received gateway is null."); log_link_info(link, "DHCP: Received gateway is null.");
else if (classless_route)
/* According to RFC 3442: If the DHCP server returns both a Classless Static Routes option and /* According to RFC 3442: If the DHCP server returns both a Classless Static Routes option and
a Router option, the DHCP client MUST ignore the Router option. */ * a Router option, the DHCP client MUST ignore the Router option. */
if (classless_route && static_route) log_link_warning(link, "Classless static routes received from DHCP server: ignoring router option");
log_link_warning(link, "Classless static routes received from DHCP server: ignoring static-route option and router option"); else {
if (r > 0 && !classless_route && !in4_addr_is_null(&router[0])) {
_cleanup_(route_freep) Route *route = NULL, *route_gw = NULL; _cleanup_(route_freep) Route *route = NULL, *route_gw = NULL;
r = route_new(&route_gw); r = route_new(&route_gw);
@ -399,20 +401,20 @@ static int link_set_dhcp_routes(Link *link) {
r = dhcp_route_configure(route, link); r = dhcp_route_configure(route, link);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not set router: %m"); return log_link_error_errno(link, r, "Could not set router: %m");
}
LIST_FOREACH(routes, rt, link->network->static_routes) { LIST_FOREACH(routes, rt, link->network->static_routes) {
if (!rt->gateway_from_dhcp) if (!rt->gateway_from_dhcp)
continue; continue;
if (rt->family != AF_INET) if (rt->family != AF_INET)
continue; continue;
rt->gw.in = router[0]; rt->gw.in = router[0];
r = dhcp_route_configure(rt, link); r = dhcp_route_configure(rt, link);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not set gateway: %m"); return log_link_error_errno(link, r, "Could not set gateway: %m");
}
} }
} }