From: Yu Watanabe Date: Mon, 12 Jul 2021 16:06:08 +0000 (+0900) Subject: network: dhcp4: also support semi-static routes with Gateway=_dhcp4 when UseGateway... X-Git-Tag: v250-rc1~949^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=0ebab55f4f7550737d3db0985c5735580e59c7e7;p=thirdparty%2Fsystemd.git network: dhcp4: also support semi-static routes with Gateway=_dhcp4 when UseGateway=no or UseRoutes=no This makes the default gateway is read from classless static routes or router option even if UseGateway=no or UseRoutes=no, and will be used when configuring semi-static routes such that specified with Gateway=_dhcp4. This also changes the behavior of RoutesToDNS= or RoutesToNTP=. Previously, the DNS or NTP servers are not in the same network, then the routes to the servers were not configured when UseGateway=no or UseRoutes=no. With this commit, the default gateway in classless static routes or router option will used to connecting the servers even if UseGateway=no or UseRoutes=no. Fixes #20208. --- diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 511e4b1bdfd..8936e68a33f 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -379,9 +379,6 @@ static int dhcp4_request_static_routes(Link *link, struct in_addr *ret_default_g assert(link->dhcp_lease); assert(ret_default_gw); - if (!link->network->dhcp_use_routes) - return 0; - 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."); @@ -406,6 +403,45 @@ static int dhcp4_request_static_routes(Link *link, struct in_addr *ret_default_g if (classless_route && static_route) log_link_debug(link, "Classless static routes received from DHCP server: ignoring static-route option"); + if (!link->network->dhcp_use_routes) { + if (!classless_route) + return 0; + + /* Even if UseRoutes=no, try to find default gateway to make semi-static routes and + * routes to DNS or NTP servers can be configured in later steps. */ + for (int i = 0; i < n; i++) { + struct in_addr dst; + uint8_t prefixlen; + + if (sd_dhcp_route_get_option(static_routes[i]) != SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE) + continue; + + r = sd_dhcp_route_get_destination(static_routes[i], &dst); + if (r < 0) + return r; + + if (in4_addr_is_set(&dst)) + continue; + + r = sd_dhcp_route_get_destination_prefix_length(static_routes[i], &prefixlen); + if (r < 0) + return r; + + if (prefixlen != 0) + continue; + + r = sd_dhcp_route_get_gateway(static_routes[i], ret_default_gw); + if (r < 0) + return r; + + break; + } + + /* Do not return 1 here, to ensure the router option can override the default gateway + * that was found. */ + return 0; + } + for (int i = 0; i < n; i++) { _cleanup_(route_freep) Route *route = NULL; struct in_addr gw; @@ -454,19 +490,15 @@ static int dhcp4_request_static_routes(Link *link, struct in_addr *ret_default_g return classless_route; } -static int dhcp4_request_gateway(Link *link, struct in_addr *ret_gw) { +static int dhcp4_request_gateway(Link *link, struct in_addr *gw) { _cleanup_(route_freep) Route *route = NULL; const struct in_addr *router; struct in_addr address; - Route *rt; int r; assert(link); assert(link->dhcp_lease); - assert(ret_gw); - - if (!link->network->dhcp_use_gateway) - return 0; + assert(gw); r = sd_dhcp_lease_get_address(link->dhcp_lease, &address); if (r < 0) @@ -484,6 +516,16 @@ static int dhcp4_request_gateway(Link *link, struct in_addr *ret_gw) { return 0; } + if (!link->network->dhcp_use_gateway) { + /* When no classless static route is provided, even if UseGateway=no, use the gateway + * address to configure semi-static routes or routes to DNS or NTP servers. Note, if + * neither UseRoutes= nor UseGateway= is disabled, use the default gateway in classless + * static routes if provided (in that case, in4_addr_is_null(gw) below is true). */ + if (in4_addr_is_null(gw)) + *gw = router[0]; + return 0; + } + /* The dhcp netmask may mask out the gateway. First, add an explicit route for the gateway host * so that we can route no matter the netmask or existing kernel route tables. */ r = dhcp4_request_route_to_gateway(link, &router[0]); @@ -508,18 +550,42 @@ static int dhcp4_request_gateway(Link *link, struct in_addr *ret_gw) { if (r < 0) return r; + /* When no classless static route is provided, or UseRoutes=no, then use the router address to + * configure semi-static routes and routes to DNS or NTP servers in later steps. */ + *gw = router[0]; + return 0; +} + +static int dhcp4_request_semi_static_routes(Link *link, const struct in_addr *gw) { + Route *rt; + int r; + + assert(link); + assert(link->dhcp_lease); + assert(link->network); + assert(gw); + + if (in4_addr_is_null(gw)) + return 0; + HASHMAP_FOREACH(rt, link->network->routes_by_section) { + _cleanup_(route_freep) Route *route = NULL; + if (!rt->gateway_from_dhcp_or_ra) continue; if (rt->gw_family != AF_INET) continue; + r = dhcp4_request_route_to_gateway(link, gw); + if (r < 0) + return r; + r = route_dup(rt, &route); if (r < 0) return r; - route->gw.in = router[0]; + route->gw.in = *gw; if (!route->protocol_set) route->protocol = RTPROT_DHCP; if (!route->priority_set) @@ -534,7 +600,6 @@ static int dhcp4_request_gateway(Link *link, struct in_addr *ret_gw) { return r; } - *ret_gw = router[0]; return 0; } @@ -653,6 +718,10 @@ static int dhcp4_request_routes(Link *link) { return log_link_error_errno(link, r, "DHCP error: Could not request gateway: %m"); } + r = dhcp4_request_semi_static_routes(link, &gw); + if (r < 0) + return log_link_error_errno(link, r, "DHCP error: Could not request routes with Gateway=_dhcp4 setting: %m"); + r = dhcp4_request_routes_to_dns(link, &gw); if (r < 0) return log_link_error_errno(link, r, "DHCP error: Could not request routes to DNS servers: %m");